package com.xbongbong.saas.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.ConfigConstant;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DefaultTypeEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.DefaultAttrPoJo;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.ItemPoJo;
import com.xbongbong.paas.field.MultiUnitItemPoJo;
import com.xbongbong.paas.field.SaasParticularAttributePoJo;
import com.xbongbong.paas.field.SubFormPoJo;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.FormDataValidateProductHelp;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.help.ProGetHelp;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.help.ProUpdateHelp;
import com.xbongbong.paas.help.TransactionHelp;
import com.xbongbong.paas.help.UserHelp;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.log.pojo.InfoArrPojo;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.pojo.AttrValuePojo;
import com.xbongbong.paas.pojo.FieldAttrEntityForImport;
import com.xbongbong.paas.pojo.FormTitlePoJo;
import com.xbongbong.paas.pojo.SummaryDataPoJo;
import com.xbongbong.paas.pojo.dto.AggSumDTO;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.FormDataDeleteBatchDTO;
import com.xbongbong.paas.pojo.dto.FormDataGetDTO;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.pojo.dto.FormDataSummaryDTO;
import com.xbongbong.paas.pojo.dto.ImportFormDataDTO;
import com.xbongbong.paas.pojo.dto.ParseSingleRowDataDTO;
import com.xbongbong.paas.pojo.dto.SaasFormSaveDTO;
import com.xbongbong.paas.pojo.dto.UserAndDepartmentGetDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.imports.CellTitlePojo;
import com.xbongbong.paas.pojo.imports.CellValuePojo;
import com.xbongbong.paas.pojo.imports.RowGroupPojo;
import com.xbongbong.paas.pojo.vo.AggSumVO;
import com.xbongbong.paas.pojo.vo.FormDataGetVO;
import com.xbongbong.paas.pojo.vo.ParseSingleRowDataVO;
import com.xbongbong.paas.pojo.vo.UserAndDepartmentGetVO;
import com.xbongbong.paas.service.PaasFormDataService;
import com.xbongbong.parent.interfaces.DynamicStrategy;
import com.xbongbong.paas.service.dynamic.crm.strategy.DynamicStrategyFactory;
import com.xbongbong.paas.service.log.crm.help.OperationLogHelp;
import com.xbongbong.paas.service.team.TeamDataHelp;
import com.xbongbong.paas.service.workflow.trigger.WorkflowFormDataOperationService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CloneUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.PageHelperUtil;
import com.xbongbong.paas.toolbox.util.RegexUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.BaseVO;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.parent.interfaces.logger.OperationLogFactory;
import com.xbongbong.parent.interfaces.logger.OperationLogHandle;
import com.xbongbong.parent.parse.data.FormDataUpdateGetAnalysisDataHelp;
import com.xbongbong.pro.applist.pojo.AppListPojo;
import com.xbongbong.pro.applist.pojo.vo.ListAppVO;
import com.xbongbong.pro.businessdata.pojo.dto.FormatExplainDTO;
import com.xbongbong.pro.businessproduct.pojo.dto.BusinessProductListDTO;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.constant.RegExConstant;
import com.xbongbong.pro.contract.pojo.dto.QuotationUpdateBatchDTO;
import com.xbongbong.pro.contract.pojo.dto.QuotationUpdateDTO;
import com.xbongbong.pro.contractproduct.pojo.dto.QuotationProductDeleteBatchDTO;
import com.xbongbong.pro.customer.pojo.dto.ChangeStatusDTO;
import com.xbongbong.pro.customer.pojo.dto.CustomerRestoreBatchDTO;
import com.xbongbong.pro.customercommunicate.pojo.dto.CustomerDynamicAddDTO;
import com.xbongbong.pro.defaultData.pojo.DefaultDataPojo;
import com.xbongbong.pro.defaultData.pojo.dto.DefaultDataDTO;
import com.xbongbong.pro.defaultData.pojo.vo.DefaultDataVO;
import com.xbongbong.pro.detailtab.pojo.DataDetailTabPojo;
import com.xbongbong.pro.detailtab.vo.DetailTabGetVO;
import com.xbongbong.pro.detailtab.vo.ProductSummaryVO;
import com.xbongbong.pro.domain.entity.LinkProductRelyEntity;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicDeleteDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicSaveDTO;
import com.xbongbong.pro.enums.AmountFlagEnum;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.QuotationErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.TemplateErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.UserTeamErrorCodeEnum;
import com.xbongbong.pro.enums.permission.enums.ProPermissionAliasEnum;
import com.xbongbong.pro.formdata.pojo.AfterSavePojo;
import com.xbongbong.pro.formdata.pojo.dto.SaasAnalysisDataDTO;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainDTO;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainInLinkItemDTO;
import com.xbongbong.pro.listbatch.pojo.dto.AddLabelDTO;
import com.xbongbong.pro.log.pojo.dto.DeleteBatchOperationLogDTO;
import com.xbongbong.pro.log.pojo.dto.DeleteOperationLogDTO;
import com.xbongbong.pro.log.pojo.dto.UpdateBatchOperationLogDTO;
import com.xbongbong.pro.message.constant.QuotationPushConstant;
import com.xbongbong.pro.message.enums.PushTypeEnum;
import com.xbongbong.pro.message.help.PushHelper;
import com.xbongbong.pro.message.pojo.PushRefTypePojo;
import com.xbongbong.pro.message.pojo.dto.MessageRabbitMqDTO;
import com.xbongbong.pro.opportunityuser.pojo.dto.QuotationUserDeleteBatchDTO;
import com.xbongbong.pro.product.pojo.dto.PagingProductDTO;
import com.xbongbong.pro.product.pojo.vo.DetailProductVO;
import com.xbongbong.pro.product.pojo.vo.PagingProductVO;
import com.xbongbong.pro.pushnotify.dto.PushNotifyDeleteDTO;
import com.xbongbong.pro.quatation.pojo.dto.QuotationEditAttrUpdateDTO;
import com.xbongbong.pro.quatation.pojo.dto.QuotationGetDTO;
import com.xbongbong.pro.quatation.pojo.dto.QuotationHistoryDTO;
import com.xbongbong.pro.quatation.pojo.vo.QuotationGetVO;
import com.xbongbong.pro.rabbitmq.producer.BaseProducer;
import com.xbongbong.pro.service.toolbox.elasticsearch.help.ProEsHelper;
import com.xbongbong.pro.thread.ThreadPoolBeanConfig;
import com.xbongbong.pro.user.pojo.ReturnUserAndDepartmentPojo;
import com.xbongbong.pro.warehouse.pojo.vo.QuotationDeleteBatchVO;
import com.xbongbong.pro.workorder.pojo.dto.QuotationDeleteBatchDTO;
import com.xbongbong.saas.analytical.impl.QuotationValidateAnalyticalServiceImpl;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.constant.TabConstant;
import com.xbongbong.saas.domain.entity.CustomerUserEntity;
import com.xbongbong.saas.domain.entity.QuotationProductEntity;
import com.xbongbong.saas.domain.entity.UserTeamEntity;
import com.xbongbong.saas.domain.entity.ext.ProductEntityExt;
import com.xbongbong.saas.domain.entity.ext.QuotationEntityExt;
import com.xbongbong.saas.enums.BusinessProductEnum;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.ContentTypeEnum;
import com.xbongbong.saas.enums.NumberTypeEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperatePageEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.ProjectLogEnum;
import com.xbongbong.saas.enums.RedundantTemplateTypeEnum;
import com.xbongbong.saas.enums.RelativeProductEnum;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.UpdateDataTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContactEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.QuotationEnum;
import com.xbongbong.saas.enums.business.SalesOpportunityEnum;
import com.xbongbong.saas.enums.dictionary.ArchivedEnum;
import com.xbongbong.saas.enums.dictionary.QuotationStatusEnum;
import com.xbongbong.saas.enums.product.OpportunityProductEnum;
import com.xbongbong.saas.enums.product.QuotationProductEnum;
import com.xbongbong.saas.help.BasicHelper;
import com.xbongbong.saas.help.ExplainHelp;
import com.xbongbong.saas.help.ImportHelper;
import com.xbongbong.saas.help.LogHandleHelp;
import com.xbongbong.saas.help.RelativeProductHelp;
import com.xbongbong.saas.help.SaasGetHelp;
import com.xbongbong.saas.help.SaasListHelp;
import com.xbongbong.saas.help.SaasUpdateHelp;
import com.xbongbong.saas.model.CustomerUserModel;
import com.xbongbong.saas.model.LinkProductRelyModel;
import com.xbongbong.saas.model.ProductModel;
import com.xbongbong.saas.model.QuotationModel;
import com.xbongbong.saas.model.QuotationProductModel;
import com.xbongbong.saas.model.QuotationUserModel;
import com.xbongbong.saas.model.SpecificationModel;
import com.xbongbong.saas.service.BusinessProductService;
import com.xbongbong.saas.service.ContractService;
import com.xbongbong.saas.service.CustomerCommunicateService;
import com.xbongbong.saas.service.OpportunityService;
import com.xbongbong.saas.service.ProductService;
import com.xbongbong.saas.service.PushNotifyService;
import com.xbongbong.saas.service.QuotationProductService;
import com.xbongbong.saas.service.QuotationService;
import com.xbongbong.saas.service.QuotationUserService;
import com.xbongbong.saas.service.UserTeamService;
import com.xbongbong.saas.service.toolbox.help.AttrDecimalPrecisionHelper;
import com.xbongbong.saas.service.toolbox.help.LogHelp;
import com.xbongbong.saas.service.toolbox.help.UserTeamHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.domain.entity.CompanyConfigEntity;
import com.xbongbong.sys.domain.entity.DepartmentEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.sys.model.UserModel;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;

import static com.xbongbong.paas.elasticsearch.constant.EsNormalConstant.MINI_MUM_SHOULD_MATCH;
import static com.xbongbong.saas.enums.RelativeProductEnum.BARCODE;
import static com.xbongbong.saas.enums.RelativeProductEnum.MEMO;
import static com.xbongbong.saas.enums.RelativeProductEnum.NAME;
import static com.xbongbong.saas.enums.RelativeProductEnum.NUM;
import static com.xbongbong.saas.enums.RelativeProductEnum.PRODUCT_NO;
import static com.xbongbong.saas.enums.RelativeProductEnum.PRODUCT_PRICE;
import static com.xbongbong.saas.enums.RelativeProductEnum.SALE_DISCOUNT;
import static com.xbongbong.saas.enums.RelativeProductEnum.SALE_PRODUCT_PRICE;
import static com.xbongbong.saas.enums.RelativeProductEnum.SPECIFICATION;
import static com.xbongbong.saas.enums.RelativeProductEnum.SUBTOTAL;
import static com.xbongbong.saas.enums.RelativeProductEnum.UNIT;
import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleOrDefaultFromFormData;
import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getIntegerOrDefaultFromFormData;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author long.rao
 * @version v1.0
 * @date 2019/8/12 19:59
 * @since v1.0
 */
@Service("quotationService")
public class QuotationServiceImpl implements QuotationService {
    private static final Logger LOG = LoggerFactory.getLogger(QuotationServiceImpl.class);

    @Resource
    private QuotationModel quotationModel;
    @Resource
    private SaasUpdateHelp saasUpdateHelp;
    @Resource
    private ThreadPoolBeanConfig threadPoolBeanConfig;
    @Resource
    private EsHelper esHelper;
    @Resource
    private UserHelp userHelp;
    @Resource
    private CustomerUserModel customerUserModel;
    @Resource
    private UserModel userModel;
    @Resource
    private UserTeamService userTeamService;
    @Resource
    private ProductModel productModel;
    @Resource
    private QuotationProductModel quotationProductModel;
    @Resource
    private ExplainHelp explainHelp;
    @Resource
    private RelativeProductHelp relativeProductHelp;
    @Resource
    private SpecificationModel specificationModel;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private QuotationProductService quotationProductService;
    @Resource
    private PushNotifyService pushNotifyService;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private QuotationUserService quotationUserService;
    @Resource
    private SaasListHelp saasListHelp;
    @Resource
    private PaasFormDataService paasFormDataService;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private ProductService productService;
    @Resource
    private AttrDecimalPrecisionHelper attrDecimalPrecisionHelper;
    @Resource
    private SaasGetHelp saasGetHelp;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private ImportHelper importHelper;
    @Resource
    @Lazy
    private CustomerCommunicateService customerCommunicateService;
    @Resource
    private PushHelper pushHelper;
    @Resource
    private BaseProducer baseProducer;
    @Resource
    private ProEsHelper proEsHelper;
    @Resource
    private QuotationUserModel quotationUserModel;
    @Resource
    private ContractService contractService;
    @Resource
    private FormDataValidateProductHelp formDataValidateProductHelp;
    @Resource
    private OpportunityService opportunityService;
    @Resource
    private QuotationService quotationService;
    @Resource
    private LinkProductRelyModel linkProductRelyModel;
    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private BusinessProductService businessProductService;
    @Resource
    private FormDataUpdateGetAnalysisDataHelp formDataUpdateGetAnalysisDataHelp;
    @Resource
    private ProUpdateHelp proUpdateHelp;
    @Resource
    private ProGetHelp proGetHelp;
    @Resource
    private LogHelp logHelp;
    @Resource
    private LogHandleHelp logHandleHelp;
    @Resource
    private QuotationValidateAnalyticalServiceImpl quotationAnalyticalService;
    @Resource
    private TeamDataHelp teamDataHelp;
    @Resource
    private UserTeamHelp userTeamHelp;
    @Resource
    private DynamicStrategyFactory dynamicStrategyFactory;
    @Resource
    private WorkflowFormDataOperationService workflowFormDataOperationService;
    @Resource
    private OperationLogFactory operationLogFactory;
    @Resource
    private OperationLogHelp operationLogHelp;
    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private TransactionHelp transactionHelp;


    @Override
    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException {
        quotationAnalyticalService.beforeSave(validateDataDTO);
    }



    @Override
    public AfterSavePojo afterSave(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        AfterSavePojo afterSavePojo = new AfterSavePojo();
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        JSONObject newData = saasFormSaveDTO.getNewData();
        JSONObject oldData = saasFormSaveDTO.getOldData();
        Long quotationId = newPaasFormDataEntity.getId();
        String corpid = newPaasFormDataEntity.getCorpid();
        Boolean isNew = saasFormSaveDTO.getIsNew();
        Long newCustomerId = FastJsonHelper.getLongFromFormData(newData, QuotationEnum.CUSTOMER_ID.getAttr());
        // 团队保存
        teamDataHelp.saveUserTeam(saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), quotationId, newPaasFormDataEntity, saasFormSaveDTO.getIsImport(), false);
//        userTeamService.saveUserTeam(saasFormSaveDTO);

        if (isNew) {
            try {
                // 新建更新客户最后联系时间
                Long lastConnectTime = DateTimeUtil.getInt();
                proUpdateHelp.jsonSetSetValueIntoFormDataById(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), corpid, newCustomerId,
                        CustomerManagementEnum.LAST_CONNECT_TIME.getAttr(), CustomerManagementEnum.LAST_CONNECT_TIME.getFieldType(), lastConnectTime);
            } catch (Exception e) {
                LOG.error("新建报价单更新客户最后联系时间", e);
            }
        }
        // 报价单关联产品保存
        if (saasFormSaveDTO.getSaasNeedRedundantAttrPoJo().getAttrCanSee(QuotationEnum.PRODUCT.getAttr())) {
            try {
                JSONArray productArray = newData.getJSONArray(QuotationEnum.PRODUCT.getAttr());
                //saveProduct(productArray, corpid, quotationId, saasFormSaveDTO.getIsImport());
                if (!Objects.equals(productArray, null)) {
                    saveProduct2(productArray, corpid, quotationId, isNew);
                }
            } catch (Exception e) {
                LOG.error("报价单保存关联产品", e);
            }
        }
        // TODO 创建项目日志
        if (isNew) {
            //创建信息
            String creatorId = newPaasFormDataEntity.getCreatorId();
            UserEntity creatorUser = userModel.getByKey(creatorId, corpid);
            String creatorUserName = Objects.isNull(creatorUser) ? "" : creatorUser.getName();
            //是否是第一次报价
            JSONObject data = newPaasFormDataEntity.getData();
            String version = data.getString(QuotationEnum.VERSION.getAttr());

            // 动态
            if(!Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(),saasFormSaveDTO.getDistributorMark())) {
                DynamicStrategy dynamicStrategy = dynamicStrategyFactory.getDynamicStrategy(ProjectLogEnum.QUOTATION_CREATE.getSubType());
                transactionHelp.afterCommitOrCommitNow(p -> {
                    dynamicStrategy.save(DynamicSaveDTO.initDynamicSaveDTO(newPaasFormDataEntity.getId(), newPaasFormDataEntity.getFormId(), saasFormSaveDTO, creatorUser, null));
                });
            }

            if (Objects.equals(version, StringConstant.DEFAULT_VERSION)) {
                //新建报价单
                if(Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(),saasFormSaveDTO.getDistributorMark())) {
                    String operate = Objects.equals(saasFormSaveDTO.getIsImport(), 1) ? I18nMessageUtil.getMessage(I18nStringConstant.IMPORTED) : I18nMessageUtil.getMessage(I18nStringConstant.ADD);
                    String communicateMemo = creatorUserName + operate + ProjectLogEnum.QUOTATION_CREATE.getName() + " :" + newPaasFormDataEntity.getSerialNo();
                    Integer subType = ProjectLogEnum.QUOTATION_CREATE.getSubType();
                    String log = I18nMessageUtil.getMessage(I18nStringConstant.QUOTATION_ADD_LOG);
                    projectLog(saasFormSaveDTO, creatorId, newCustomerId, communicateMemo, subType, log);
                }

            } else {
                // 新版本，将上个版本的isNew置为0
                BoolQueryBuilder filter = boolQuery()
                        .filter(termQuery("corpid.keyword", corpid))
                        .filter(termQuery("del", 0))
                        .filter(termQuery(QuotationEnum.getEsAttr4Keyword(QuotationEnum.IS_NEW), BasicConstant.ONE))
                        .filter(termQuery(QuotationEnum.getEsAttr4Keyword(QuotationEnum.GROUP_NUMBER), FastJsonHelper.getStringOrDefaultFromFormData(data, QuotationEnum.GROUP_NUMBER.getAttr(), "")))
                        .filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())))
                        .filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_QUOTATION.getType()))
                        .mustNot(termQuery(FieldTypeEnum.DATAID.getAlias(), quotationId));
                List<SortBuilder> sortBuilderList = new ArrayList<>();
                sortBuilderList.add(new FieldSortBuilder("addTime").order(SortOrder.DESC));
                List<QuotationEntityExt> quotationEntityExts = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_QUOTATION, filter, QuotationEntityExt.class, Collections.singletonList(FieldTypeEnum.DATAID.getAlias()), sortBuilderList);
                if (!quotationEntityExts.isEmpty()) {
                    QuotationEntityExt quotationEntityExt = quotationEntityExts.get(0);
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put(QuotationEnum.IS_NEW.getAttr(), 0);
                    UpdateDataEntity updateData = ExplainUtil.getUpdateData(quotationEntityExt.getDataId(), jsonObject, corpid);
                    quotationModel.updateBatch(Collections.singletonList(updateData), corpid);
                }

                //报价单新版本
                if(Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(),saasFormSaveDTO.getDistributorMark())) {
                    String operate = Objects.equals(saasFormSaveDTO.getIsImport(), 1) ? I18nMessageUtil.getMessage(I18nStringConstant.IMPORTED) : I18nMessageUtil.getMessage(I18nStringConstant.ADD);
                    String communicateMemo = creatorUser.getName() + operate + ProjectLogEnum.QUOTATION_NEW_VERSION.getName() + " :" + newPaasFormDataEntity.getSerialNo();
                    Integer subType = ProjectLogEnum.QUOTATION_NEW_VERSION.getSubType();
                    String log = I18nMessageUtil.getMessage(I18nStringConstant.QUOTATION_NEW_VERSION_LOG);
                    projectLog(saasFormSaveDTO, creatorId, newCustomerId, communicateMemo, subType, log);
                }

                // 新版本操作日志
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_NEW_VERSION), saasFormSaveDTO.getLoginUserName(), XbbRefTypeEnum.QUOTATION.getName(), newPaasFormDataEntity.getSerialNo());
                mongoLogHelp.buildLog(corpid, saasFormSaveDTO.getUserId(), saasFormSaveDTO.getLoginUserName(), OperateModuleTypeEnum.QUOTATION, OperateTypeEnum.NEW_VERSION,
                        quotationId.toString(), newPaasFormDataEntity.getSerialNo(), memo, saasFormSaveDTO.getHttpHeader());
            }

            try {
                // 报价单创建消息推送
                QuotationEntityExt quotationEntityExt = new QuotationEntityExt();
                BeanUtil.copyProperties(newPaasFormDataEntity, quotationEntityExt);
                List<String> pushUserList = pushHelper.getUserIdListByPushSetRule(corpid, PushTypeEnum.QUOTATION_ADD_PUSH.getCode(), PushTypeEnum.QUOTATION_ADD_PUSH.getSubCode(), creatorUser, quotationEntityExt);
                PushRefTypePojo.Options options = new PushRefTypePojo.Options(quotationEntityExt.getAppId(), quotationEntityExt.getMenuId(), quotationEntityExt.getFormId(), quotationId, Collections.singletonList(quotationId), SaasMarkEnum.SAAS.getCode(), saasFormSaveDTO.getBusinessType(), saasFormSaveDTO.getSubBusinessType());
                MessageRabbitMqDTO messageRabbitMqDTO = new MessageRabbitMqDTO(corpid, pushUserList, Collections.singletonList(quotationId), 0, null, I18nMessageUtil.getMessage(QuotationPushConstant.QUOTATAION_ADD_TITLE), String.format(I18nMessageUtil.getMessage(QuotationPushConstant.QUOTATAION_ADD_CONTENT), creatorUser.getName(), quotationEntityExt.getSerialNo()), null, options);
                baseProducer.sendMessage(PushTypeEnum.QUOTATION_ADD_PUSH, messageRabbitMqDTO);
            } catch (Exception e) {
                LOG.error("报价单创建消息推送", e);
            }
        }
        try {
            // 报价状态变更消息推送
            String oldStatus = FastJsonHelper.getStringOrDefaultFromFormData(oldData, QuotationEnum.STATUS.getAttr(), "");
            String newStatus = FastJsonHelper.getStringOrDefaultFromFormData(newData, QuotationEnum.STATUS.getAttr(), "");
            String name = FastJsonHelper.getStringOrDefaultFromFormData(newData, QuotationEnum.NAME.getAttr(), "");
            if (!Objects.equals(oldStatus, newStatus)) {
                Map<String, FieldAttrEntity> explainMap = saasFormSaveDTO.getExplainMap();
                if (Objects.isNull(explainMap)) {
                    PaasFormExplainEntity byBusinessType = paasFormExplainModel.getByBusinessType(XbbRefTypeEnum.QUOTATION.getCode(), corpid);
                    explainMap = ExplainUtil.getExplainMapByAttr(byBusinessType.getExplains(), QuotationEnum.STATUS.getAttr());
                }
                FieldAttrEntity statusAttrEntity = explainMap.get(QuotationEnum.STATUS.getAttr());
                if (Objects.nonNull(statusAttrEntity)) {
                    List<ItemPoJo> items = statusAttrEntity.getItems();
                    for (ItemPoJo itemPoJo: items) {
                        if (Objects.equals(itemPoJo.getValue(), newStatus)) {
                            newStatus = itemPoJo.getText();
                        }
                    }
                }
                QuotationEntityExt quotationEntity = new QuotationEntityExt();
                BeanUtil.copyProperties(newPaasFormDataEntity, quotationEntity);
                List<String> pushUserList = pushHelper.getUserIdListByPushSetRule(corpid, PushTypeEnum.QUOTATION_STATUS_PUSH.getCode(), PushTypeEnum.QUOTATION_STATUS_PUSH.getSubCode(), saasFormSaveDTO.getLoginUser(), quotationEntity);
                PushRefTypePojo.Options options = new PushRefTypePojo.Options(quotationEntity.getAppId(), quotationEntity.getMenuId(), quotationEntity.getFormId(), quotationId, Collections.singletonList(quotationId), SaasMarkEnum.SAAS.getCode(), saasFormSaveDTO.getBusinessType(), saasFormSaveDTO.getSubBusinessType());
                MessageRabbitMqDTO messageRabbitMqDTO = new MessageRabbitMqDTO(corpid, pushUserList, Collections.singletonList(quotationId), 0, null, I18nMessageUtil.getMessage(QuotationPushConstant.QUOTATAION_CHANGE_TITLE), String.format(I18nMessageUtil.getMessage(QuotationPushConstant.QUOTATAION_CHANGE_CONTENT), saasFormSaveDTO.getLoginUserName(), name, newStatus), null, options);
                baseProducer.sendMessage(PushTypeEnum.QUOTATION_STATUS_PUSH, messageRabbitMqDTO);
            }
        } catch (Exception e) {
            LOG.error("报价单保存时报价状态变更消息推送", e);
        }
        return afterSavePojo;
    }

    private void projectLog(SaasFormSaveDTO saasFormSaveDTO, String creatorId, Long newCustomerId, String communicateMemo, Integer subType, String log) {
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        JSONObject newData = saasFormSaveDTO.getNewData();
        String corpid = newPaasFormDataEntity.getCorpid();
        Long quotationId = newPaasFormDataEntity.getId();
        //拼装
        try {
            CustomerDynamicAddDTO customerDynamicAddDTO = new CustomerDynamicAddDTO();
            String customerName = newData.getString(QuotationEnum.CUSTOMER_NAME.getAttr());
            customerDynamicAddDTO.setCorpid(corpid);
            customerDynamicAddDTO.setUserId(creatorId);
            customerDynamicAddDTO.setCustomerId(newCustomerId);
            customerDynamicAddDTO.setCustomerName(customerName);
            customerDynamicAddDTO.setMemo(communicateMemo);
            customerDynamicAddDTO.setCommunicateBusinessText(newPaasFormDataEntity.getSerialNo());
            customerDynamicAddDTO.setCommunicateBusinessType(XbbRefTypeEnum.QUOTATION.getCode());
            customerDynamicAddDTO.setDataId(quotationId);
            customerDynamicAddDTO.setLogType(subType);
            customerDynamicAddDTO.setDistributorMark(saasFormSaveDTO.getDistributorMark());
            customerCommunicateService.addCustomerDynamic(customerDynamicAddDTO);
        } catch (Exception e) {
            LOG.error(log, e);
        }
    }

    private void saveProduct2(JSONArray productArray, String corpid, Long quotationId, Boolean isNew) throws XbbException {
        Map<Long,QuotationProductEntity> originProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (!isNew){
            List<QuotationProductEntity> dbList = quotationProductModel.getProductsByQuoId(quotationId, corpid, Arrays.asList(DelEnum.NORMAL.getDel(), DelEnum.APPROVE_FAILED.getDel()));
            dbList.forEach(item -> {
                originProductMap.put(item.getId(),item);
            });
        }

        List<QuotationProductEntity> insertList = new ArrayList<>();
        List<QuotationProductEntity> updateList = new ArrayList<>();
        List<QuotationProductEntity> delList = new ArrayList<>();
        Map<Long, PaasFormDataEntityExt> productMap = formDataValidateProductHelp.product2saveMap(corpid,productArray);
        // 产品排序
        Integer sort = 0;
        for (int i = 0; i < productArray.size(); i++) {
            JSONObject jsonObject = productArray.getJSONObject(i);
            sort++;
            // 页面传入的产品id
            Long pageProductId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
            Long businessProductId = jsonObject.getLong(BusinessConstant.PRODUCT_SUB_ID);
            boolean addProductFlag = formDataValidateProductHelp.addProductFlag(businessProductId);
            // 产品数量
            Double productNum = jsonObject.getDouble(QuotationProductEnum.NUM.getAttr());
            Double price = jsonObject.getDouble(QuotationProductEnum.SELLING_PRICE.getAttr());
            price = price != null ? price : 0;
            // 折扣：默认为100%
            Double discount = jsonObject.getDouble(QuotationProductEnum.DISCOUNT.getAttr());
            discount = discount == null ? 100 : discount;
            // 备注
            String memo = jsonObject.getString(QuotationProductEnum.MEMO.getAttr());
            JSONObject productData = productMap.get(pageProductId).getData();
            QuotationProductEntity quotationProductEntity;
            if (addProductFlag) {
                quotationProductEntity = new QuotationProductEntity();
                quotationProductEntity.setAddTime(DateTimeUtil.getInt());
                quotationProductEntity.setUpdateTime(DateTimeUtil.getInt());
                insertList.add(quotationProductEntity);
            } else if (originProductMap.containsKey(businessProductId)) {
                quotationProductEntity = originProductMap.get(businessProductId);
                quotationProductEntity.setUpdateTime(DateTimeUtil.getInt());
                if (Objects.equals(DelEnum.APPROVE_FAILED.getDel(), quotationProductEntity.getDel())) {
                    quotationProductEntity.setDel(DelEnum.NORMAL.getDel());
                }
                updateList.add(quotationProductEntity);
                originProductMap.remove(businessProductId);
                productData.put(SelectProductEnum.PRICE.getAttr(),quotationProductEntity.getHistoricalPrice());
            } else {
                continue;
            }
            quotationProductEntity.setCorpid(corpid);
            quotationProductEntity.setQuotationId(quotationId);
            quotationProductEntity.setParentId(productData.getLong(ProductEnum.PARENT_ID.getAttr()));
            quotationProductEntity.setProductId(pageProductId);
            quotationProductEntity.setProductNum(productNum);
            quotationProductEntity.setProductName(productData.getString(ProductEnum.NAME.getAttr()));
            quotationProductEntity.setProductNo(productData.getString(ProductEnum.PRODUCT_NO.getAttr()));
            quotationProductEntity.setPrice(price);
//            quotationProductEntity.setProductUnit(productData.getString(ProductEnum.UNIT.getAttr()));
            quotationProductEntity.setDiscount(discount);
            quotationProductEntity.setSpecification(productData.getString(ProductEnum.SPECIFICATION_LINK_TEXT.getAttr()));
//            contractProductEntity.setProductThumbnail();
            quotationProductEntity.setMemo(memo);
            quotationProductEntity.setBarcode(productData.getString(ProductEnum.BARCODE.getAttr()));
            quotationProductEntity.setCost(productData.getDouble(ProductEnum.COST.getAttr()));
            quotationProductEntity.setSort(sort);
            quotationProductEntity.setHistoricalPrice(productData.getDouble(ProductEnum.PRICE.getAttr()));
            Integer enableMultiUnit = productData.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr());
            if (Objects.equals(enableMultiUnit, 1)) {
                formDataValidateProductHelp.setBusinessUnit(jsonObject, quotationProductEntity);
                quotationProductEntity.setProductUnit(jsonObject.getString(SelectProductEnum.UNIT.getAttr()));
            } else {
                quotationProductEntity.setProductUnit(productData.getString(ProductEnum.UNIT.getAttr()));
                jsonObject.put(QuotationProductEnum.UNIT.getAttr(),productData.getString(ProductEnum.UNIT.getAttr()));
            }
            quotationProductEntity.setData(jsonObject);
        }
        // 批量插入
        quotationProductModel.insertBatch(insertList);
        // 批量编辑
        quotationProductModel.updateBatch(updateList, corpid);

        List<Long> deleteList = new ArrayList<>();
        for (Map.Entry<Long, QuotationProductEntity> entry : originProductMap.entrySet()) {
            QuotationProductEntity delProduct = entry.getValue();
            delProduct.setDel(1);
            deleteList.add(delProduct.getId());
        }
        quotationProductModel.deleteBatch(deleteList, corpid, DelEnum.DELETE.getDel());
    }



    @Override
    public void formatAddExplain(FormatExplainDTO formatExplainDTO) throws XbbException {
        List<FieldAttrEntity> entities = formatExplainDTO.getExplainList();
        String corpid = formatExplainDTO.getCorpid();
        for (FieldAttrEntity fieldAttrEntity : entities) {
            String attr = fieldAttrEntity.getAttr();
            if (Objects.equals(attr, QuotationEnum.PRODUCT.getAttr())) {
                explainHelp.formatSelectProductExplains(fieldAttrEntity, XbbRefTypeEnum.QUOTATION, corpid, OperatePageEnum.NEW.getCode(), false);
                fieldAttrEntity.setSupportScanning(BasicConstant.ONE);
                CompanyConfigEntity priceConfig = companyConfigModel.getByConfigAlias(CompanyConfigEnum.PRICE_MANAGE.getAlias(), corpid);
                if (priceConfig != null && Objects.equals(priceConfig.getConfigValue(), "1")) {
                    SaasParticularAttributePoJo saasParticularAttributePoJo = new SaasParticularAttributePoJo();
                    saasParticularAttributePoJo.setIsOpenPrice(BasicConstant.ONE);
                    fieldAttrEntity.setSaasParticularAttributePoJo(saasParticularAttributePoJo);
                }
            } else if (Objects.equals(attr, QuotationEnum.PRODUCT_TOTAL.getAttr())) {
                fieldAttrEntity.setEditable(BasicConstant.ZERO);
            } else if (Objects.equals(attr, QuotationEnum.QUOTATION_NO.getAttr())) {
                fieldAttrEntity.setEditable(BasicConstant.ZERO);
            }
        }
    }


    @Override
    public QuotationGetVO getNewVersion(QuotationGetDTO quotationGetDTO) throws XbbException {
        QuotationGetVO quotationGetVO = new QuotationGetVO();
        FormDataGetVO formDataGetVO = new FormDataGetVO();
        Long dataId = quotationGetDTO.getDataId();
        String corpid = quotationGetDTO.getCorpid();
        FormDataGetDTO formDataGetDTO = new FormDataGetDTO();
        BeanUtil.copyProperties(quotationGetDTO, formDataGetDTO);
        formDataGetVO = paasFormDataService.get(formDataGetDTO);
        JSONObject data = formDataGetVO.getData();
        //版本号+1,同步生产新的报价单编号
        Double oldVersion = data.getDouble(QuotationEnum.VERSION.getAttr()) + 1;
        String newVersion = oldVersion.toString();
        String groupNumber = data.getString(QuotationEnum.GROUP_NUMBER.getAttr());
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(groupNumber);
        stringBuilder.append(newVersion);
        String serialNo = stringBuilder.toString();
        data.put(QuotationEnum.VERSION.getAttr(), newVersion);
        data.put(QuotationEnum.QUOTATION_NO.getAttr(), serialNo);
        formDataGetVO.setData(data);
        BeanUtil.copyProperties(formDataGetVO, quotationGetVO);
        quotationGetVO.setGroupNumber(groupNumber);
        quotationGetVO.setSerialNo(serialNo);
        return quotationGetVO;

    }

    @Override
    public QuotationDeleteBatchVO deleteBatch(QuotationDeleteBatchDTO quotationDeleteBatchDTO) throws XbbException {
        QuotationDeleteBatchVO quotationDeleteBatchVO = new QuotationDeleteBatchVO();
        List<Long> idIn = quotationDeleteBatchDTO.getDataIdList();
        String corpid = quotationDeleteBatchDTO.getCorpid();
        BoolQueryBuilder productBuilder = boolQuery();
        productBuilder.filter(termQuery("corpid.keyword", corpid));
        productBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        productBuilder.filter(termsQuery(StringConstant.DATA_ID, idIn));
        List<String> fieldList = Arrays.asList(StringConstant.SAAS_LINK_BUSINESS_ID, FieldTypeEnum.SERIALNO.getAlias(), StringConstant.JSON_DATA);
        List<PaasFormDataEntityExt> quotationList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_QUOTATION, productBuilder, PaasFormDataEntityExt.class, fieldList);
        if (Objects.isNull(quotationList)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }

        Map<String, String> noAndName= new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<String> groupNumbers = new ArrayList<>();
        // 报价单组号
        String groupNumber = "";
        Integer isNew;
        String groupNumberAttr = QuotationEnum.GROUP_NUMBER.getAttr();
        String isNewAttr = QuotationEnum.IS_NEW.getAttr();
        try {
            for (PaasFormDataEntityExt item: quotationList) {
                String no = item.getSerialNo();
                String name = FastJsonHelper.getStringOrDefaultFromFormData(item.getData(), QuotationEnum.NAME.getAttr(), "");
                noAndName.put(no, name);
                groupNumber = FastJsonHelper.getStringOrDefaultFromFormData(item.getData(), groupNumberAttr, "");
                isNew = getIntegerOrDefaultFromFormData(item.getData(), isNewAttr, BasicConstant.ZERO);
                if (Objects.equals(isNew, BasicConstant.ONE)) {
                    groupNumbers.add(groupNumber);
                }
            }

            if (!idIn.isEmpty()) {
                if(BasicConstant.ONE.equals(quotationDeleteBatchDTO.getSingleFlag())
                        && BasicConstant.ONE.equals(idIn.size())){
                    paasEsModel.delete(idIn.get(0),corpid,IndexTypeEnum.IDX_SAAS_QUOTATION,null);
                    quotationModel.deleteByKey(idIn.get(0),corpid);
                }else {
                    paasEsModel.deleteBatch(idIn, corpid, DelEnum.DELETE.getDel(), IndexTypeEnum.IDX_SAAS_QUOTATION);
                    quotationModel.deleteBatch(idIn, corpid);
                }
                quotationDeleteBatchVO.setDeleteIds(idIn);
                if (!groupNumbers.isEmpty()) {
                    // 删除报价单，如果它是最新的报价单，那么将其上一个版本的报价单变成最新的报价单（即isNew字段置为1）
                    // 查询最近版本的报价单，然后封装条件isNew为0，创建时间倒序，再用map过滤只拿相同组号中的第一条的数据
                    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
                    BoolQueryBuilder boolQueryBuilder = boolQuery();
                    boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
                    boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                    boolQueryBuilder.filter(termsQuery(QuotationEnum.getEsAttr4Keyword(QuotationEnum.GROUP_NUMBER), groupNumbers));
                    boolQueryBuilder.filter(termQuery(QuotationEnum.getEsAttr4Keyword(QuotationEnum.IS_NEW), BasicConstant.ZERO));
                    boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_QUOTATION.getType()));
                    sourceBuilder.query(boolQueryBuilder);
                    sourceBuilder.sort(new FieldSortBuilder(StringConstant.ADD_TIME).order(SortOrder.DESC));
                    PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 0, PaasConstant.ES_MAX_PAGE_SIZE);
                    SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_QUOTATION.getIndex());
                    searchRequest.source(sourceBuilder);
                    XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest, PaasFormDataEntityExt.class);
                    Map<String, Long> quotationMap = new HashMap<>(idIn.size());
                    List<Long> needUpdateIds = new ArrayList<>();
                    esEntities.getContent().forEach(item-> {
                        if (item.getData().get(groupNumberAttr) != null && !quotationMap.containsKey(item.getData().getString(groupNumberAttr))) {
                            quotationMap.put(item.getData().getString(groupNumberAttr), item.getId());
                            needUpdateIds.add(item.getId());
                        }
                    });
                    if (!needUpdateIds.isEmpty()) {
                        proUpdateHelp.updateByIds(XbbRefTypeEnum.QUOTATION.getCode(), corpid, needUpdateIds, isNewAttr, BasicConstant.ONE);
                    }
                }

                // 删除报价单产品
                QuotationProductDeleteBatchDTO quotationProductDeleteBatchDTO = new QuotationProductDeleteBatchDTO();
                BeanUtil.copyProperties(quotationDeleteBatchDTO, quotationProductDeleteBatchDTO, true);
                quotationProductDeleteBatchDTO.setQuotationIdIn(idIn);
                quotationProductService.deleteBatch(quotationProductDeleteBatchDTO);

                // 删除报价单团队关系
                QuotationUserDeleteBatchDTO quotationUserDeleteBatchDTO = new QuotationUserDeleteBatchDTO();
                BeanUtil.copyProperties(quotationDeleteBatchDTO, quotationUserDeleteBatchDTO);
                quotationUserDeleteBatchDTO.setQuotationIdIn(idIn);
                quotationUserService.deleteBatch(quotationUserDeleteBatchDTO);

                PushNotifyDeleteDTO pushNotifyDeleteDTO = new PushNotifyDeleteDTO();
                BeanUtil.copyProperties(quotationDeleteBatchDTO, pushNotifyDeleteDTO);
                pushNotifyDeleteDTO.setNeedDelNotifyIdList(idIn);
                pushNotifyDeleteDTO.setBusinessType(XbbRefTypeEnum.QUOTATION.getCode());
                pushNotifyService.deletePushNotify(pushNotifyDeleteDTO);
            }
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.DELETE;
            if (Objects.equals(1, quotationDeleteBatchDTO.getIsBusinessRule())) {
                operateTypeEnum = OperateTypeEnum.RULE_DELETE;
            }
            //生成删除日志(区分单个删除和批量删除)
            String userId = quotationDeleteBatchDTO.getUserId();
            String userName = quotationDeleteBatchDTO.getLoginUserName();
            List<String> list = new ArrayList<>();
            Iterator<String> iterator = noAndName.keySet().iterator();
            while (iterator.hasNext()) {
                String key = iterator.next();
                String value = noAndName.get(key);
                if(StringUtil.isEmpty(value)){
                    list.add(key);
                } else {
                    StringBuilder sb = new StringBuilder();
                    sb.append(key).append("（").append(value).append("）");
                    list.add(sb.toString());
                }
            }
            String nameStr = StringUtils.join(list, "、");
            Integer singleFlag = quotationDeleteBatchDTO.getSingleFlag();
            if(Objects.equals(0,singleFlag)||idIn.size() > 1){
                List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                InfoArrPojo infoArrPojo = new InfoArrPojo();
                infoArrPojo.setTitle(OperationLogHelp.setDetailTitle());
                infoArrPojo.setContent(nameStr);
                infoArrPojoList.add(infoArrPojo);
                DeleteBatchOperationLogDTO deleteBatchOperationLogDTO = new DeleteBatchOperationLogDTO( corpid,  userId,  userName, null,  operateTypeEnum,
                        null,  nameStr,  null,  idIn.size(),quotationDeleteBatchDTO.getHttpHeader(),quotationDeleteBatchDTO.getFormId(),quotationDeleteBatchDTO.getBusinessType());
                OperationLogHandle operationLogHandle = operationLogFactory.getOperationLogHandle(SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.QUOTATION.getCode());
                operationLogHandle.deleteBatch(infoArrPojoList,deleteBatchOperationLogDTO);
            } else if (Objects.equals(singleFlag, 1)&& CollectionsUtil.isNotEmpty(idIn)){
                DeleteOperationLogDTO deleteOperationLogDTO = new DeleteOperationLogDTO(corpid,userId,userName,null,operateTypeEnum,idIn.get(0).toString(),nameStr,null,quotationDeleteBatchDTO.getHttpHeader(),quotationDeleteBatchDTO.getFormId(),quotationDeleteBatchDTO.getBusinessType());
                OperationLogHandle operationLogHandle = operationLogFactory.getOperationLogHandle(SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.QUOTATION.getCode());
                operationLogHandle.delete(deleteOperationLogDTO);
            }

            // 删除报价单动态
            try {
                if (!Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(), quotationDeleteBatchDTO.getDistributorMark())) {
                    DynamicStrategy dynamicStrategy = dynamicStrategyFactory.getDynamicStrategy(ProjectLogEnum.QUOTATION_DELETE.getSubType());
                    FormDataDeleteBatchDTO formDataDeleteBatchDTO = BeanUtil.copyProperties(quotationDeleteBatchDTO, FormDataDeleteBatchDTO.class, true);
                    dynamicStrategy.batchDelete(DynamicDeleteDTO.initDynamicDeleteDTO(formDataDeleteBatchDTO, quotationList.stream().map(PaasFormDataEntityExt::getId).collect(Collectors.toList()), quotationList));
                }
            } catch (Exception e) {
                LOG.error("删除报价单动态失败：", e);
            }
        } catch (Exception e) {
            LOG.error("quotationServiceImpl.deleteBatch 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }

        return quotationDeleteBatchVO;
    }

    @Override
    public DetailTabGetVO getHistory(QuotationHistoryDTO quotationHistoryDTO) throws XbbException {
        String groupNumber = "";
        String corpid = quotationHistoryDTO.getCorpid();
        Long dataId = quotationHistoryDTO.getDataId();
        Integer businessType = quotationHistoryDTO.getBusinessType();
        //分页
        Integer page = quotationHistoryDTO.getPage();
        Integer pageSize = quotationHistoryDTO.getPageSize();
        DetailTabGetVO detailTabGetVO = new DetailTabGetVO();
        JSONArray needShowAttrArr = new JSONArray();
        JSONObject summaryObj = new JSONObject();
        JSONObject data = new JSONObject();
        long num;
        String platform = quotationHistoryDTO.getPlatform();
        QuotationEntityExt quotationEntityExt = quotationModel.getByKey(dataId, corpid);
        if (quotationEntityExt == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100404);
        }
        PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByBusinessType(RedundantTemplateTypeEnum.QUOTATION.getCode(), corpid);
        if (Objects.isNull(paasFormExplainEntity)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        String explains = paasFormExplainEntity.getExplains();
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explains, null);
        groupNumber = Objects.toString(quotationEntityExt.getData().get(QuotationEnum.GROUP_NUMBER.getAttr()));
        //筛选版本（只展示当前版本之前的版本）
        QuotationEntityExt quotationEntityExt1 = quotationModel.getByKey(dataId, corpid);
        Long quoatationTime = quotationEntityExt1.getAddTime();
        BoolQueryBuilder filter = boolQuery()
                .filter(termQuery("corpid.keyword", corpid))
                .filter(termQuery("del", 0))
                .filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())))
                .filter(termsQuery("data." + QuotationEnum.GROUP_NUMBER.getAttr() + ".keyword", groupNumber))
                .filter(rangeQuery("addTime").lt(quoatationTime));
        filter.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_QUOTATION.getType()));
        List<SortBuilder> sortBuilderList = new ArrayList<>();
        sortBuilderList.add(new FieldSortBuilder("addTime").order(SortOrder.DESC));
        List<QuotationEntityExt> quotationEntityExts = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_QUOTATION, filter, QuotationEntityExt.class, null, sortBuilderList);
        //时间筛选
        JSONArray addTimeArray = quotationHistoryDTO.getAddTime();
        if (addTimeArray != null && !addTimeArray.isEmpty()) {
            List<Object> list = BasicHelper.timeStrToValueList(addTimeArray);
            Long startTime = Long.valueOf(Objects.toString(list.get(BasicConstant.ZERO), ""));
            Long endTime = Long.valueOf(Objects.toString(list.get(BasicConstant.ONE), ""));
            quotationEntityExts = quotationEntityExts.stream().filter(item ->
                    item.getAddTime() > startTime && item.getAddTime() < endTime).collect(Collectors.toList());
        }
        num = quotationEntityExts.size();
        if (Objects.equals(StringConstant.PLATFORM_WEB, platform)) {

            // 获取报价单对应产品
            List<Long> quotationProductIds = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            quotationProductIds.add(-1L);
            quotationEntityExts.forEach(item -> quotationProductIds.add(item.getDataId()));
            List<QuotationProductEntity> quotationProducts = quotationProductModel.getQuotationProductByQuotationIdIn(corpid, quotationProductIds);

            // 从产品表获取对应产品
            List<Long> proudctIdIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            quotationProducts.forEach(item -> proudctIdIn.add(item.getProductId()));
            Map<Long, ProductEntityExt> productMap = productModel.getProductMapByIdIn(corpid, proudctIdIn, null);

            Map<String, String> statusMap = ExplainUtil.getItemsMap(explainMap, QuotationEnum.STATUS.getAttr());

            UserAndDepartmentGetDTO userAndDepartmentGetDTO = new UserAndDepartmentGetDTO();
            BeanUtil.copyProperties(quotationHistoryDTO, userAndDepartmentGetDTO);
            Map<String, UserEntity> userMap = userHelp.getUserMap(userAndDepartmentGetDTO);

            Boolean quotationNoHide = false;
            Boolean quotationPersonHide = false;
            Boolean discountHide = false;
            Boolean amountHide = false;
            Boolean statusHide = false;
            Boolean addTimeHide = false;
            //协同团队
            Map<Long, List<String>> mainUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long, List<String>> coUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            userTeamService.getUserIdMap(quotationProductIds, corpid, XbbRefTypeEnum.QUOTATION.getCode(), false, mainUserMap, coUserMap);
            HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
            BeanUtil.copyProperties(quotationHistoryDTO, handlerExplainDTO);
            handlerExplainDTO.setExplainList(new ArrayList<>(explainMap.values()));

            for (QuotationEntityExt entityExt : quotationEntityExts) {
                handlerExplainDTO.setCreatorId(entityExt.getCreatorId());
                handlerExplainDTO.setOwnerId(mainUserMap.getOrDefault(entityExt.getDataId(), new ArrayList<>()));
                handlerExplainDTO.setCoUserId(coUserMap.getOrDefault(entityExt.getDataId(), new ArrayList<>()));
                quotationNoHide = ExplainUtil.fieldAttrHide(explainMap.getOrDefault(QuotationEnum.QUOTATION_NO.getAttr(), new FieldAttrEntity()), handlerExplainDTO);
                quotationPersonHide = ExplainUtil.fieldAttrHide(explainMap.getOrDefault(QuotationEnum.QUOTATION_PERSON.getAttr(), new FieldAttrEntity()), handlerExplainDTO);
                discountHide = ExplainUtil.fieldAttrHide(explainMap.getOrDefault(QuotationEnum.DISCOUNT.getAttr(), new FieldAttrEntity()), handlerExplainDTO);
                amountHide = ExplainUtil.fieldAttrHide(explainMap.getOrDefault(QuotationEnum.AMOUNT.getAttr(), new FieldAttrEntity()), handlerExplainDTO);
                statusHide = ExplainUtil.fieldAttrHide(explainMap.getOrDefault(QuotationEnum.STATUS.getAttr(), new FieldAttrEntity()), handlerExplainDTO);
                addTimeHide = ExplainUtil.fieldAttrHide(explainMap.getOrDefault(QuotationEnum.ADD_TIME.getAttr(), new FieldAttrEntity()), handlerExplainDTO);


                JSONObject needShowAttr = new JSONObject();
                JSONObject content = new JSONObject();
                Double productKind = 0.0;
                Double productNum = 0.0;
                Double discount = 0.0;
                String productImgs = ConfigConstant.DEFAULT_PRO_PIC;
                JSONArray productImg = new JSONArray();
                String discount4Show = "";
                Long quotationId = entityExt.getDataId();
                if (entityExt.getData() == null) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
                }
                data = entityExt.getData();
                for (QuotationProductEntity quotationProduct : quotationProducts) {
                    if (Objects.equals(quotationId, quotationProduct.getQuotationId())) {
                        productKind++;
                        double rate = quotationProduct.getRate() == null ? 1D : quotationProduct.getRate();
                        productNum = Arith.add(productNum, Arith.div(quotationProduct.getProductNum(), rate));
                    }
                    if (quotationProducts.indexOf(quotationProduct) == 0) {
                        Long productId = quotationProduct.getProductId();
                        ProductEntityExt product = productMap.get(productId);
                        if (product != null) {
                            JSONObject productDataList = product.getData();
                            try {
                                productImg = FastJsonHelper.getJsonArrOrDefaultFromFormData(productDataList, ProductEnum.THUMBNAIL.getAttr(), new JSONArray());
                            } catch (Exception e) {
                                productImg = new JSONArray();
                            }
                            if (productImg.isEmpty()) {
                                try {
                                    productImg = FastJsonHelper.getJsonArrOrDefaultFromFormData(productDataList, ProductEnum.PRODUCT_IMGS.getAttr(), new JSONArray());
                                } catch (Exception e) {
                                    productImg = new JSONArray();
                                }
                            }
                            if (!productImg.isEmpty()){
                                productImgs = productImg.getString(productImg.size() - 1);
                            }
                        }
                    }
                }
                String middle4Show = String.format(I18nMessageUtil.getMessage(I18nStringConstant.PRODUCT_NUM), productKind, productNum);
                discount = getDoubleOrDefaultFromFormData(data, QuotationEnum.DISCOUNT.getAttr(), 0D);
                //根据解释回显百分比还是整数
                if (explainMap.get(QuotationEnum.DISCOUNT.getAttr()) != null) {
                    FieldAttrEntity fieldAttrEntity = new FieldAttrEntity();
                    fieldAttrEntity = explainMap.get(QuotationEnum.DISCOUNT.getAttr());
                    if (Objects.equals(fieldAttrEntity.getNumberType(), NumberTypeEnum.RATE.getCode())) {
                        discount4Show = discount * 100 + "%";
                    } else {
                        discount4Show = discount + "";
                    }

                }
                //报价金额
                Double amount;
                amount = getDoubleOrDefaultFromFormData(data, QuotationEnum.AMOUNT.getAttr(), 0D);
                String amountStr = amount + I18nMessageUtil.getMessage(TabConstant.YUAN);
                //千份位
                FieldAttrEntity fieldAttrEntity = null;
                if(explainMap.containsKey(QuotationEnum.AMOUNT.getAttr())){
                    fieldAttrEntity = explainMap.get(QuotationEnum.AMOUNT.getAttr());
                }
                if(Objects.nonNull(fieldAttrEntity)){
                    if(AmountFlagEnum.YES.getType().equals(fieldAttrEntity.getAmountFlag())){
                        Object amountThousandth = AttrDecimalPrecisionHelper.parseThousandth(amount,fieldAttrEntity.getAccuracy());
                        amountStr = amountThousandth + I18nMessageUtil.getMessage(TabConstant.YUAN);
                    }
                }
                content.put(ParameterConstant.TYPE, ContentTypeEnum.PRODUCT.getName());
                content.put(BusinessConstant.AVATAR, productImgs);
                content.put(BusinessConstant.COUNT, middle4Show);
                if (amountHide) {
                    amountStr = "";
                }
                content.put(BusinessConstant.MONEY, amountStr);
                if (discountHide) {
                    discount4Show = "";
                }
                content.put(BusinessConstant.DISCOUNT, discount4Show);
                DataDetailTabPojo dataDetailTabPojo = new DataDetailTabPojo();
                dataDetailTabPojo.setAppId(entityExt.getAppId());
                dataDetailTabPojo.setDataId(entityExt.getDataId());
                dataDetailTabPojo.setMenuId(entityExt.getMenuId());
                dataDetailTabPojo.setFormId(entityExt.getFormId());
                dataDetailTabPojo.setSaasMark(SaasMarkEnum.SAAS.getCode());
                dataDetailTabPojo.setBusinessType(XbbRefTypeEnum.QUOTATION.getCode());

                data = entityExt.getData();
                data.put(QuotationEnum.OWNER_ID.getAttr(), entityExt.getOwnerId());
                summaryObj.put(BusinessConstant.ATTR_NAME, QuotationEnum.QUOTATION_PERSON.getAttrName());
                if (quotationPersonHide) {
                    summaryObj.put(StringConstant.VALUE, "");
                } else {
                    summaryObj.put(StringConstant.VALUE, saasUpdateHelp.getUserOrDefaultFromFormData(entityExt.getData(), userMap, QuotationEnum.QUOTATION_PERSON.getAttr(), ""));
                }
                JSONArray summaryList = new JSONArray();
                summaryList.add(summaryObj);
                String status = Objects.toString(entityExt.getData().get(QuotationEnum.STATUS.getAttr()), "");
                String statusValue = statusMap.getOrDefault(status, "");
                if (!quotationNoHide) {
                    needShowAttr.put(StringConstant.SAAS_LINK_BUSINESS_NAME, entityExt.getSerialNo());
                } else {
                    needShowAttr.put(StringConstant.SAAS_LINK_BUSINESS_NAME, " ");
                }
                needShowAttr.put(BusinessConstant.CONTENT, content);
                needShowAttr.put(BusinessConstant.SUMMARY_LIST, summaryList);
                needShowAttr.put(BusinessConstant.STATUS_LIST, "");
                if (statusHide) {
                    statusValue = "";
                }
                needShowAttr.put(BusinessConstant.STATUS, statusValue);
                needShowAttr.put(ParameterConstant.DATE, entityExt.getAddTime());
                if (!addTimeHide) {
                    needShowAttr.put(ParameterConstant.DATE_FORMAT, DateTimeUtil.getStringEpochSecond(entityExt.getAddTime(), DateTimeUtil.SDFDate));
                } else {
                    needShowAttr.put(ParameterConstant.DATE_FORMAT, "");
                }
                needShowAttr.put(TabConstant.ENTITY, dataDetailTabPojo);
                needShowAttr.put(StringConstant.SAAS_LINK_BUSINESS_LINK_TYPE, quotationHistoryDTO.getBusinessType());
                needShowAttr.put(TabConstant.SAAS_MARK, SaasMarkEnum.SAAS.getCode());
                needShowAttrArr.add(needShowAttr);
            }
        } else {
            for (QuotationEntityExt entityExt : quotationEntityExts) {
                JSONObject needShowAttr = new JSONObject();
                data = entityExt.getData();
                String discount4Show = "";
                Double discountNum = 0.0;
                //整单折扣
                JSONObject discount = new JSONObject();
                discount.put(TabConstant.NAME_ATTR, QuotationEnum.DISCOUNT.getAttrName());
                if (data.getDouble(QuotationEnum.DISCOUNT.getAttr()) != null) {
                    discountNum = data.getDouble(QuotationEnum.DISCOUNT.getAttr());
                }
                //根据解释回显百分比还是整数
                if (explainMap.get(QuotationEnum.DISCOUNT.getAttr()) != null) {
                    FieldAttrEntity fieldAttrEntity = new FieldAttrEntity();
                    fieldAttrEntity = explainMap.get(QuotationEnum.DISCOUNT.getAttr());
                    if (Objects.equals(fieldAttrEntity.getNumberType(), NumberTypeEnum.RATE.getCode())) {
                        discount4Show = discountNum * 100 + "%";
                    } else {
                        discount4Show = discountNum + "";
                    }

                }
                discount.put(StringConstant.VALUE, discount4Show);

                //负责人
                UserAndDepartmentGetDTO userAndDepartmentGetDTO = new UserAndDepartmentGetDTO();
                BeanUtil.copyProperties(quotationHistoryDTO, userAndDepartmentGetDTO);
                Map<String, UserEntity> userMap = userHelp.getUserMap(userAndDepartmentGetDTO);
                //报价人
                JSONObject quotationPerson = new JSONObject();
                quotationPerson.put(TabConstant.NAME_ATTR, QuotationEnum.QUOTATION_PERSON.getAttrName());
                quotationPerson.put(StringConstant.VALUE, saasUpdateHelp.getUserOrDefaultFromFormData(data, userMap, QuotationEnum.QUOTATION_PERSON.getAttr(), ""));
                //报价日期
                JSONObject quotationTime = new JSONObject();
                quotationTime.put(TabConstant.NAME_ATTR, QuotationEnum.QUOTATION_TIME.getAttrName());
                if (data.getDate(QuotationEnum.QUOTATION_TIME.getAttr()) != null) {
                    Integer intTime = 0;
                    intTime = data.getInteger(QuotationEnum.QUOTATION_TIME.getAttr());
                    String timeStr = DateUtil.getString(intTime, DateUtil.SDFDate);
                    quotationTime.put(StringConstant.VALUE, timeStr);
                } else {
                    quotationTime.put(StringConstant.VALUE, "");
                }
                //状态
                String status = Objects.toString(data.get(QuotationEnum.STATUS.getAttr()), "");
                String statusValue = QuotationStatusEnum.getName(status);
                //报价金额
                Double amount;
                amount = getDoubleOrDefaultFromFormData(data, QuotationEnum.AMOUNT.getAttr(), 0D);
                String amountStr = amount + I18nMessageUtil.getMessage(TabConstant.YUAN);
                //千份位
                FieldAttrEntity fieldAttrEntity = null;
                if(explainMap.containsKey(QuotationEnum.AMOUNT.getAttr())){
                    fieldAttrEntity = explainMap.get(QuotationEnum.AMOUNT.getAttr());
                }
                if(Objects.nonNull(fieldAttrEntity)){
                    if(AmountFlagEnum.YES.getType().equals(fieldAttrEntity.getAmountFlag())){
                        Object amountThousandth = AttrDecimalPrecisionHelper.parseThousandth(amount,fieldAttrEntity.getAccuracy());
                        amountStr = amountThousandth + I18nMessageUtil.getMessage(TabConstant.YUAN);
                    }
                }
                //跳转需要的参数
                DataDetailTabPojo dataDetailTabPojo = new DataDetailTabPojo();
                dataDetailTabPojo.setAppId(entityExt.getAppId());
                dataDetailTabPojo.setDataId(entityExt.getDataId());
                dataDetailTabPojo.setMenuId(entityExt.getMenuId());
                dataDetailTabPojo.setFormId(entityExt.getFormId());
                dataDetailTabPojo.setSaasMark(SaasMarkEnum.SAAS.getCode());
                dataDetailTabPojo.setBusinessType(XbbRefTypeEnum.QUOTATION.getCode());
                dataDetailTabPojo.setSubBusinessType(XbbRefTypeEnum.QUOTATION.getCode());
                needShowAttr.put(TabConstant.ENTITY, dataDetailTabPojo);
                needShowAttr.put(TabConstant.LABELS, statusValue);
                needShowAttr.put(TabConstant.RIGHT_TOP, amountStr);
                needShowAttr.put(TabConstant.NAME, entityExt.getSerialNo());
                needShowAttr.put(TabConstant.OWNERID, saasUpdateHelp.getUserOrDefaultFromFormData(entityExt.getData(), userMap, QuotationEnum.OWNER_ID.getAttr(), ""));
                needShowAttr.put(QuotationEnum.DISCOUNT.getSaasAttr(), discount);
                needShowAttr.put(QuotationEnum.QUOTATION_PERSON.getSaasAttr(), quotationPerson);
                needShowAttr.put(QuotationEnum.QUOTATION_TIME.getSaasAttr(),quotationTime);
                needShowAttrArr.add(needShowAttr);
            }
        }
        detailTabGetVO.setNeedShowAttr(needShowAttrArr);
        PageHelper pageHelper = new PageHelper(page, pageSize);
        pageHelper.setRowsCount((int) num);
        detailTabGetVO.setPageHelper(pageHelper);
        return detailTabGetVO;
    }

    /**
     * 获取客户的团队
     *
     * @param customerId 客户id
     * @param corpid 公司id
     * @throws
     * @author long.rao
     * @date 2019-08-15 19:44
     */
    private List<UserEntity> getCustomerUserList(Long customerId, String corpid) {
        List<UserEntity> list = new ArrayList<>();
        Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("customerId", customerId);
        param.put("corpid", corpid);

        param.put("del", 0);
        param.put("orderByStr", "is_main desc");
        List<CustomerUserEntity> customerUserList = customerUserModel.findEntitys(param);

        List<String> userIdIn = new ArrayList<>();
        for(CustomerUserEntity customerUser : customerUserList){
            userIdIn.add(customerUser.getUserId());
        }
        userIdIn.add("-1");
        param.clear();
        param.put("userIdIn", userIdIn);
        param.put("corpid", corpid);
        param.put("del", 0);
        List<UserEntity> userList = userModel.findEntitys(param);

        Map<String, UserEntity> userMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for(UserEntity user : userList){
            userMap.put(user.getUserId(), user);
        }

        for(CustomerUserEntity customerUser : customerUserList){
            if(userMap.containsKey(customerUser.getUserId())){
                UserEntity userEntity = (UserEntity) CloneUtil.deepClone(userMap.get(customerUser.getUserId()));
                userEntity.setIsMain(customerUser.getIsMain());
                list.add(userEntity);
            }
        }
        return list;
    }

    @Override
    public void formatProduct4Show(JSONObject dataList, SaasAnalysisDataDTO saasAnalysisDataDTO) throws XbbException {
        if (dataList == null || saasAnalysisDataDTO == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028);
        }
        String corpid = saasAnalysisDataDTO.getCorpid();
        Long quotationId = saasAnalysisDataDTO.getDataId();
        JSONObject productFinalObj = new JSONObject();
        JSONArray productArray = new JSONArray();
        // 获取关联产品
        List<QuotationProductEntity> quoProductList = new ArrayList<>();
        if (saasAnalysisDataDTO.getForProcess()) {
            JSONArray productArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(FastJsonHelper.getJsonObjectOrDefaultFromFormData(dataList, QuotationEnum.PRODUCT.getAttr(), new JSONObject()), StringConstant.PRODUCT_LIST, new JSONArray());
            Map<Long, ProductEntityExt> productMap = productModel.getProductMap(corpid, productArr);
            quotationModel.getProductList(corpid, quoProductList, productArr, productMap);
        } else {
            quoProductList = quotationProductModel.getProductsByQuoId(quotationId, corpid);
        }

        if (quoProductList == null || quoProductList.size() == 0) {
            productFinalObj.put(StringConstant.PRODUCT_LIST, productArray);
            dataList.put(QuotationEnum.PRODUCT.getAttr(), productFinalObj);
            return;
        }
        Set<Long> productIds = new HashSet<>();

        for (QuotationProductEntity entity : quoProductList) {
            productIds.add(entity.getProductId());
        }
        List<PaasFormDataEntityExt> paasFormDataESList = productService.getProductListById(productIds,corpid, null);
        Set<Long> parentIdInSet = new HashSet<>();
        Map<Long, PaasFormDataEntityExt> productEntityMap = new HashMap<>(paasFormDataESList.size());
        paasFormDataESList.forEach((item)->{
            productEntityMap.put(item.getDataId(), item);
            JSONObject data = item.getData();
            if (Objects.nonNull(data) && Objects.nonNull(data.getLong(ProductEnum.PARENT_ID.getAttr()))) {
                parentIdInSet.add(data.getLong(ProductEnum.PARENT_ID.getAttr()));
            }
        });
        // 获取父类产品
        List<PaasFormDataEntityExt> parentProductList = productService.getProductListById(parentIdInSet, corpid, null);
        Map<Long, PaasFormDataEntityExt> parentProductMap = new HashMap<>(paasFormDataESList.size());
        parentProductList.forEach((item)->{
            parentProductMap.put(item.getDataId(), item);
        });

        // 获取关联产品需要展示的字段
        BusinessProductEnum businessProductEnum = BusinessProductEnum.getByCode(XbbRefTypeEnum.QUOTATION.getCode());
        // 用于存放当前启用的产品模板解释的map
        Map<String, FieldAttrEntity> nowProductExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, FieldAttrEntity> nowBomProductExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        explainHelp.getRelativeProductExplainsFromDB(corpid, nowProductExplainMap, nowBomProductExplainMap);

        Map<Integer, JSONObject> productMap = new TreeMap<>();
        if (businessProductEnum != BusinessProductEnum.UNKNOW) {
            List<RelativeProductEnum> businessProductEnumList = businessProductEnum.getList();
            for (QuotationProductEntity entity : quoProductList) {
                JSONArray attrArray = new JSONArray();
                JSONObject productObj = new JSONObject();
                Long productId = entity.getProductId();
                if (productEntityMap.containsKey(productId)) {
                    JSONObject productData = productEntityMap.get(productId).getData();
                    Long parentId = productData.getLong(ProductEnum.PARENT_ID.getAttr());
                    PaasFormDataEntityExt parentDataEntity = parentProductMap.get(parentId);

                    boolean priceHide = false;
                    if (parentDataEntity != null) {
                        //协同团队
                        Map<Long, List<String>> mainUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        Map<Long, List<String>> coUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        userTeamService.getUserIdMap(Collections.singletonList(parentId), corpid, XbbRefTypeEnum.PRODUCT.getCode(), false, mainUserMap, coUserMap);
                        HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
                        BeanUtil.copyProperties(saasAnalysisDataDTO, handlerExplainDTO);
                        handlerExplainDTO.setCreatorId(parentDataEntity.getCreatorId());
                        handlerExplainDTO.setOwnerId(mainUserMap.getOrDefault(parentDataEntity.getDataId(), new ArrayList<>()));
                        handlerExplainDTO.setCoUserId(coUserMap.getOrDefault(parentDataEntity.getDataId(), new ArrayList<>()));
                        handlerExplainDTO.setExplainList(new ArrayList<>(nowProductExplainMap.values()));
                        priceHide = ExplainUtil.isFieldNeedHide(nowProductExplainMap.getOrDefault(ProductEnum.PRICE.getSaasAttr(), new FieldAttrEntity()), handlerExplainDTO);
                    }

                    String productNo = FastJsonHelper.getStringOrDefaultFromFormData(parentDataEntity.getData(), ProductEnum.PRODUCT_NO.getAttr(), "");




                    Double price = entity.getPrice();
                    price = price == null ? 0 : price;
                    Double productNum = entity.getProductNum();
                    productNum = productNum == null ? 0 : productNum;
                    String memo = entity.getMemo();
                    Double discount = entity.getDiscount();
                    for (RelativeProductEnum productEnum : businessProductEnumList) {
                        String saasAttr;
                        if (Objects.equals(productEnum, PRODUCT_PRICE) || Objects.equals(productEnum, SALE_PRODUCT_PRICE) || Objects.equals(productEnum, SUBTOTAL)) {
                            saasAttr = ProductEnum.PRICE.getSaasAttr();
                        } else {
                            saasAttr = productEnum.getSaasAttr();
                        }
                        FieldAttrEntity fieldAttrEntity = null;
                        if (nowProductExplainMap.containsKey(saasAttr)) {
                            fieldAttrEntity = nowProductExplainMap.get(saasAttr);
                        }
                        switch (productEnum) {
                            case NAME:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(NAME, entity.getProductName(), fieldAttrEntity));
                                break;
                            case PRODUCT_NO:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(PRODUCT_NO, productNo, fieldAttrEntity));
                                break;
                            case BARCODE:
                                String barcode = productData.getString(ProductEnum.BARCODE.getAttr());
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(BARCODE, barcode, fieldAttrEntity));
                                break;
                            case SPECIFICATION:
                                // 格式化规格
                                String specification = specificationModel.joinSpecification(entity.getSpecification());
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(SPECIFICATION, specification, fieldAttrEntity));
                                break;
                            case PRODUCT_PRICE:
                                Double productPrice = productData.getDouble(ProductEnum.PRICE.getAttr());
                                productPrice = productPrice == null ? 0 : productPrice;
                                // TODO 需要重新处理
//                                boolean priceVisible = paasFormExplainService.checkVisibleByAttr(explainList, ProductEnum.PRICE.getAttr());
                                JSONObject priceObj = saasUpdateHelp.formatSelectProduct4Show(PRODUCT_PRICE, productPrice, fieldAttrEntity);
                                if (priceObj != null) {
                                    priceObj.put("hidePrice", priceHide);
                                    JsonHelperUtil.addToJSONArray(attrArray, priceObj);
                                }
                                if (Objects.nonNull(dataList.get("hidePrice"))) {
                                    dataList.put("hidePrice", priceHide);
                                }
                                break;
                            case SALE_DISCOUNT:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(SALE_DISCOUNT, discount, fieldAttrEntity));
                                break;
                            case SALE_PRODUCT_PRICE:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(SALE_PRODUCT_PRICE, price, fieldAttrEntity));
                                break;
                            case NUM:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(NUM, productNum, fieldAttrEntity));
                                break;
                            case MEMO:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(MEMO, memo, fieldAttrEntity));
                                break;
                            case UNIT:
                                String productUnit = entity.getProductUnit();
                                String unitStr = productModel.getProductUnitTextByValue(productUnit, fieldAttrEntity);
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(UNIT, unitStr, fieldAttrEntity));
                                break;
                            case SUBTOTAL:
                                Double subTotal = price * productNum;
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(SUBTOTAL, subTotal, fieldAttrEntity));
                                break;
                            case THUMBNAIL:
                                JSONArray thumbnailArray = productData.getJSONArray(ProductEnum.THUMBNAIL.getAttr());
                                if (Objects.isNull(thumbnailArray) || thumbnailArray.isEmpty()) {
                                    thumbnailArray = new JSONArray();
                                    thumbnailArray.add(StringConstant.DEFAULT_IMAGES);
                                }
                                productObj.put("thumbnail",thumbnailArray);
                                break;
                            default:
                                break;
                        }
                        productObj.put("result", attrArray);
                        productObj.put(StringConstant.SAAS_LINK_BUSINESS_ID, entity.getProductId());
                        productObj.put(StringConstant.BUSINESS_PRODUCT_ID, entity.getId());
                        productObj.put("parentId", entity.getParentId());
                        productObj.put("estimateCost", entity.getCost());
                    }
                }
                productMap.put(entity.getSort(), productObj);
            }
            // 产品排序
            for (JSONObject jsonObject : productMap.values()) {
                productArray.add(jsonObject);
            }
            productFinalObj.put(StringConstant.PRODUCT_LIST, productArray);
            dataList.put(QuotationEnum.PRODUCT.getAttr(), productFinalObj);
        }
    }


    @Override
    public ListAppVO formatQuotationAppList(FormDataListDTO formDataListDTO, List<PaasFormDataEntityExt> esEntities, Integer totalCount) throws XbbException {
        List<AppListPojo> appListPojos = new ArrayList<>();
        String corpid = formDataListDTO.getCorpid();
        List<Long> idIn = new ArrayList<>();
        idIn.add(-1L);
        for (PaasFormDataEntityExt customer : esEntities) {
            idIn.add(customer.getDataId());
        }
        //有提醒的报价单
        List<Long> pushNotifyList = new ArrayList<>();
        saasListHelp.getPushNotify(idIn, corpid, XbbRefTypeEnum.QUOTATION.getCode(), pushNotifyList);
        String amount;
        String amountAttr = QuotationEnum.AMOUNT.getAttr();
        String unit = I18nMessageUtil.getMessage(TabConstant.YUAN);
        Map<String, FieldAttrEntity> explainMap = formDataListDTO.getExplainMap();
        FieldAttrEntity contactAmountExplain = explainMap.get(amountAttr);
        boolean amountVisible = false;
        if (contactAmountExplain != null && Objects.equals(contactAmountExplain.getVisible(), 1)) {
            amountVisible = true;
        }
        for (PaasFormDataEntityExt entityExt : esEntities) {
            JSONObject data = entityExt.getData();
            Long quotationId = entityExt.getDataId();
            Long appId = entityExt.getAppId();
            Long menuId = entityExt.getMenuId();
            Long formId = entityExt.getFormId();

            JSONObject superScript = new JSONObject();
            JSONObject others = new JSONObject();
            amount = FastJsonHelper.getStringOrDefaultFromFormData(data, amountAttr, "0");
            amount += unit;
            if (!amountVisible) {
                amount = StringConstant.INVISIBLE_VALUE;
            }
            /*-- 其他 -*/
            others.put("amount", amount);

            List<SummaryDataPoJo> summaryList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.SUMMARY_LIST, new JSONArray()).toJavaList(SummaryDataPoJo.class);
            List<SummaryDataPoJo> lablesList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.LABELS_LIST, new JSONArray()).toJavaList(SummaryDataPoJo.class);
            List<FormTitlePoJo> titleList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.TITLE_LIST, new JSONArray()).toJavaList(FormTitlePoJo.class);
            // 角标 -
            superScript.put("message", pushNotifyList.contains(quotationId) ? 1 : 0);
            // isAchived为1代表归档，2代表未归档
            Integer isAchived = getIntegerOrDefaultFromFormData(data, QuotationEnum.ARCHIVED.getAttr(), ArchivedEnum.UN_ARCHIVED.getCode());
            if(Objects.equals(isAchived, ArchivedEnum.ARCHIVED.getCode())){
                superScript.put("archived", ArchivedEnum.ARCHIVED.getCode());
            }
            //app系统关联数据展示需要 others 和 superScript
            data.put("others",others);
            data.put("superScript",superScript);
            appListPojos.add(new AppListPojo(quotationId, titleList, summaryList, superScript, lablesList, others, appId, menuId, formId));
        }
        ListAppVO listAppVO = new ListAppVO();
        listAppVO.setList(appListPojos);
        listAppVO.setTotalCount(totalCount);
        return  listAppVO;
    }


    @Override
    public void formatLinkAddExplain(HandlerExplainInLinkItemDTO handlerExplainInLinkItemDTO) throws XbbException {
        JSONObject linkFormData = handlerExplainInLinkItemDTO.getLinkFormData();
        Long linkDataId = handlerExplainInLinkItemDTO.getLinkDataId();
        String corpid = handlerExplainInLinkItemDTO.getCorpid();
        List<FieldAttrEntity> explainList = handlerExplainInLinkItemDTO.getExplainList();
        FieldAttrEntity linkCustomerField = new FieldAttrEntity();
        FieldAttrEntity linkContactField = new FieldAttrEntity();
        FieldAttrEntity linkOpportunityField = new FieldAttrEntity();
        FieldAttrEntity linkProductField = new FieldAttrEntity();
        FieldAttrEntity contractAmountField = new FieldAttrEntity();
        FieldAttrEntity quotationAmountField = new FieldAttrEntity();
        FieldAttrEntity productTotalField = new FieldAttrEntity();
        FieldAttrEntity discountField = new FieldAttrEntity();
        FieldAttrEntity otherExpenseField = new FieldAttrEntity();
        FieldAttrEntity discountAmountField = new FieldAttrEntity();
        FieldAttrEntity linkQuotationField = new FieldAttrEntity();
        FieldAttrEntity linkGroupNumberField = new FieldAttrEntity();
        for (FieldAttrEntity fieldAttrEntity : explainList) {
            if (Objects.equals(fieldAttrEntity.getAttr(), QuotationEnum.CUSTOMER_ID.getAttr())) {
                linkCustomerField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), QuotationEnum.CONTACT_ID.getAttr())) {
                linkContactField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), QuotationEnum.OPPORTUNITY_ID.getAttr())) {
                linkOpportunityField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), QuotationEnum.PRODUCT.getAttr())) {
                linkProductField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), QuotationEnum.AMOUNT.getAttr())) {
                quotationAmountField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), QuotationEnum.GROUP_NUMBER.getAttr())) {
                linkGroupNumberField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), QuotationEnum.PRODUCT_TOTAL.getAttr())) {
                productTotalField = fieldAttrEntity;
            }
        }
        Long customerId = 0L;
        RedundantTemplateTypeEnum redundantTemplateTypeEnum = RedundantTemplateTypeEnum.getByCode(handlerExplainInLinkItemDTO.getLinkBusinessType());
        switch (redundantTemplateTypeEnum) {
            case CUSTOMER:
                String customerName = FastJsonHelper.getStringOrDefaultFromFormData(linkFormData, CustomerManagementEnum.NAME.getAttr(), "");
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, customerName));
                linkGroupNumberField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, handlerExplainInLinkItemDTO.getGroupNumber()));
                break;
            case CONTACT:
                String contactName = FastJsonHelper.getStringOrDefaultFromFormData(linkFormData, ContactEnum.NAME.getAttr(), "");
                linkContactField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, contactName));
                JSONArray linkCustomerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData, ContactEnum.CUSTOMER_NAME.getAttr(), new JSONArray());
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkCustomerArr));
                break;
            case SALES_OPPORTUNITY:
                String opportunityNo = handlerExplainInLinkItemDTO.getPaasFormDataEntityExt().getSerialNo();
                linkOpportunityField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, opportunityNo));
                JSONArray opportunityLinkCustomerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData, SalesOpportunityEnum.CUSTOMER_NAME.getAttr(), new JSONArray());
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(opportunityLinkCustomerArr));
                JSONArray contactArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData, SalesOpportunityEnum.CONTACT_NAME.getAttr(), new JSONArray());
                linkContactField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(contactArr));
                linkGroupNumberField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, handlerExplainInLinkItemDTO.getGroupNumber()));
                /*JSONObject productListObj = new JSONObject();
                JSONArray productList = new JSONArray();
                List<OpportunityProductEntity> opportunityProductEntityList = opportunityProductModel.getProductsByOppId(linkDataId, corpid);
                Double productTotals = 0D;
                for (OpportunityProductEntity opportunityProductEntity : opportunityProductEntityList) {
                    JSONObject product = new JSONObject();
                    product.put("parentId", opportunityProductEntity.getParentId());
                    product.put(StringConstant.SAAS_LINK_BUSINESS_ID, opportunityProductEntity.getProductId());
                    product.put(StringConstant.NUM,  opportunityProductEntity.getProductNum());
                    product.put(RelativeProductEnum.SALE_DISCOUNT.getSaasAttr(), opportunityProductEntity.getDiscount());
                    product.put(RelativeProductEnum.SALE_PRODUCT_PRICE.getSaasAttr(), opportunityProductEntity.getPrice());
                    product.put("estimateCost",opportunityProductEntity.getCost());
                    productList.add(product);

                    productTotals = Arith.add(productTotals, Arith.mul(opportunityProductEntity.getProductNum(), opportunityProductEntity.getPrice()));
                }
                productListObj.put(StringConstant.PRODUCT_LIST, productList);
                productListObj.put(BusinessConstant.OTHERS, new JSONObject());*/
                JSONObject contractDataList= new JSONObject();
//                contractDataList.put(QuotationEnum.PRODUCT.getAttr(), productListObj);
//                SaasAnalysisDataDTO saasAnalysisDataDTO = new SaasAnalysisDataDTO();
//                saasAnalysisDataDTO.setForProcess(true);
//                saasAnalysisDataDTO.setBusinessType(XbbRefTypeEnum.CONTRACT.getCode());
//                BeanUtil.copyProperties(handlerExplainInLinkItemDTO, saasAnalysisDataDTO);
                opportunityService.formatProduct4Show2(linkDataId,corpid,contractDataList, UpdateDataTypeEnum.LINK_ADD);
                JSONArray productArray = formDataValidateProductHelp.otherProductToAnother(contractDataList,linkProductField,QuotationEnum.PRODUCT.getAttr(),SalesOpportunityEnum.PRODUCTS.getAttr(),corpid, handlerExplainInLinkItemDTO.getLoginUser(), handlerExplainInLinkItemDTO.getBusinessType(), handlerExplainInLinkItemDTO.getLinkBusinessType());
                // 关联产品自定义字段联动
                LinkProductRelyEntity linkProductRelyEntity = linkProductRelyModel.getByAttrAndFormIdAndLinkFormId(corpid, QuotationEnum.PRODUCT.getAttr(), handlerExplainInLinkItemDTO.getFormId(), handlerExplainInLinkItemDTO.getSourceFormId(), DelEnum.NORMAL.getDel());
                UserAndDepartmentGetDTO userAndDepartmentGetDTO = new UserAndDepartmentGetDTO();
                BeanUtil.copyProperties(handlerExplainInLinkItemDTO, userAndDepartmentGetDTO);
                UserAndDepartmentGetVO userAndDepartmentGetVO = userHelp.getUserDepartmentMap(userAndDepartmentGetDTO);
                Map<String, UserEntity> userMap = userAndDepartmentGetVO.getUserMap();
                Map<String, DepartmentEntity> departmentMap = userAndDepartmentGetVO.getDepartmentMap();
                DefaultAttrPoJo productDefaultAttr = linkProductField.getDefaultAttr();
                String defaultType = productDefaultAttr.getDefaultType();
                if (Objects.nonNull(defaultType) && Objects.equals(defaultType, DefaultTypeEnum.PRODUCT_DATA_RELY.getAlias()) && Objects.nonNull(linkProductRelyEntity)) {
                    // 源单解释
                    Map<String, FieldAttrEntity> sourceExplainMap = null;
                    // 当前表单解释
                    Map<String, FieldAttrEntity> thisExplainMap = null;
                    // 当前表单某个关联产品解释
                    Map<String, FieldAttrEntity> subThisExplainMap = null;
                    // 源单某个关联产品解释
                    Map<String, FieldAttrEntity> subSourceExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    // 当前表单某个关联产品子字段与源单某个关联产品对应关系
                    Map<String, String> thisToTarget = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    for (Object o : contractDataList.getJSONArray(SalesOpportunityEnum.PRODUCTS.getAttr())) {
                        JSONObject contractData = (JSONObject) o;
                        // 源数据表单
                        PaasFormExplainEntity paasFormExplainEntity = proFormHelp.getExplainEntity(corpid, linkProductRelyEntity.getSourceFormId(), linkProductRelyEntity.getSourceBusinessType());
                        List<FieldAttrEntity> sourceExplainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
                        sourceExplainMap = ExplainUtil.getExplainMapByList(sourceExplainList, null);
                        // 当前表单解释
                        PaasFormExplainEntity displayFormExplain = proFormHelp.getExplainEntity(corpid, linkProductRelyEntity.getFormId(), linkProductRelyEntity.getBusinessType());
                        thisExplainMap = ExplainUtil.getExplainMap(displayFormExplain.getExplains(), null);
                        subThisExplainMap = businessProductService.getProductRelyMap(QuotationEnum.PRODUCT.getAttr(), linkProductRelyEntity, sourceExplainMap, thisExplainMap, subSourceExplainMap, thisToTarget);
                        if (Objects.nonNull(contractData) && !thisToTarget.isEmpty()) {
                            ParseSingleRowDataDTO parseSingleRowDataDTO = new ParseSingleRowDataDTO();
                            parseSingleRowDataDTO.setDataJsonObject(contractData);
                            parseSingleRowDataDTO.setExplainMap(subSourceExplainMap);
                            parseSingleRowDataDTO.setUserMap(userMap);
                            parseSingleRowDataDTO.setDepartmentMap(departmentMap);
                            ParseSingleRowDataVO parseSingleRowDataVO = formDataUpdateGetAnalysisDataHelp.parseSingleRowData(parseSingleRowDataDTO);
                            if (Objects.isNull(parseSingleRowDataVO)) {
                                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PARSE_SINGLE_ROW_DATA_FAILED);
                            }
                            JSONObject result = parseSingleRowDataVO.getResult();
                            JSONObject thisData = businessProductService.formatThisFormData(subThisExplainMap, thisToTarget, result);
                            for (int i = 0; i < productArray.size(); i++) {
                                JSONObject jsonObject = productArray.getJSONObject(i);
                                if (Objects.equals(jsonObject.getLongValue(BusinessConstant.RELY_PRODUCT_SUB_ID), contractData.getLongValue(BusinessConstant.RELY_PRODUCT_SUB_ID))) {
                                    jsonObject.putAll(thisData);
                                    break;
                                }
                            }
                        }
                    }
                }
                linkProductField.setDefaultAttr(saasUpdateHelp.setDefaultValue(productArray));
                linkProductField.getDefaultAttr().setDefaultType(defaultType);
                DefaultAttrPoJo defaultAttr = quotationAmountField.getDefaultAttr();
                defaultAttr.setUseLinkValue(BasicConstant.ONE);
                defaultAttr.setLinkFormValue(getDoubleOrDefaultFromFormData(linkFormData, SalesOpportunityEnum.ESTIMATE_AMOUNT.getAttr(), 0D));
                quotationAmountField.setDefaultAttr(defaultAttr);

                /*DefaultAttrPoJo totalDefault = productTotalField.getDefaultAttr();
                totalDefault.setUseLinkValue(BasicConstant.ONE);
                totalDefault.setLinkFormValue(productTotals);
                productTotalField.setDefaultAttr(totalDefault);*/
                break;
            case QUOTATION:
                // 合同关联报价单设置默认值
                String quotationNo = handlerExplainInLinkItemDTO.getPaasFormDataEntityExt().getSerialNo();
                linkQuotationField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, quotationNo));
                // 合同关联客户设置默认值
                JSONArray quotationLinkCustomerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData, QuotationEnum.CUSTOMER_ID.getAttr(), new JSONArray());
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(quotationLinkCustomerArr));
                // 合同关联联系人设置默认值
                JSONArray quotationContactArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData, QuotationEnum.CONTACT_ID.getAttr(), new JSONArray());
                linkContactField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(quotationContactArr));
                //// 合同关联产品设置默认值
                /*JSONObject productListObject = new JSONObject();
                JSONArray productLists = new JSONArray();
                List<QuotationProductEntity> quotationProductEntityList = quotationProductModel.getProductsByQuoId(linkDataId, corpid);
                for (QuotationProductEntity quotationProductEntity : quotationProductEntityList) {
                    JSONObject product = new JSONObject();
                    product.put("parentId", quotationProductEntity.getParentId());
                    product.put(StringConstant.SAAS_LINK_BUSINESS_ID, quotationProductEntity.getProductId());
                    product.put(StringConstant.NUM,  quotationProductEntity.getProductNum());
                    product.put(RelativeProductEnum.SALE_DISCOUNT.getSaasAttr(), quotationProductEntity.getDiscount());
                    product.put(RelativeProductEnum.SALE_PRODUCT_PRICE.getSaasAttr(), quotationProductEntity.getPrice());
                    product.put("estimateCost",quotationProductEntity.getCost());
                    productLists.add(product);
                }
                productListObject.put(StringConstant.PRODUCT_LIST, productLists);
                productListObject.put(BusinessConstant.OTHERS, new JSONObject());*/
                JSONObject quotationDataList= new JSONObject();
                /*quotationDataList.put(ContractEnum.PRODUCT.getAttr(), productListObject);
                SaasAnalysisDataDTO saasAnalysis = new SaasAnalysisDataDTO();
                saasAnalysis.setForProcess(true);
                saasAnalysis.setBusinessType(XbbRefTypeEnum.CONTRACT.getCode());
                BeanUtil.copyProperties(handlerExplainInLinkItemDTO, saasAnalysis);*/
                quotationService.formatProduct4Show2(linkDataId,corpid,quotationDataList, UpdateDataTypeEnum.LINK_ADD);
                JSONArray productArray1 = formDataValidateProductHelp.otherProductToAnother(quotationDataList,linkProductField,QuotationEnum.PRODUCT.getAttr(),SalesOpportunityEnum.PRODUCTS.getAttr(),corpid, handlerExplainInLinkItemDTO.getLoginUser(), handlerExplainInLinkItemDTO.getBusinessType(), handlerExplainInLinkItemDTO.getLinkBusinessType());
                linkProductField.setDefaultAttr(saasUpdateHelp.setDefaultValue(productArray1));
                // 合同金额设置默认值
                DefaultAttrPoJo quotationAmount = contractAmountField.getDefaultAttr();
                quotationAmount.setUseLinkValue(BasicConstant.ONE);
                quotationAmount.setLinkFormValue(getDoubleOrDefaultFromFormData(linkFormData, QuotationEnum.AMOUNT.getAttr(), 0D));
                contractAmountField.setDefaultAttr(quotationAmount);
                // 合同整单折扣设置默认值
                DefaultAttrPoJo quotationDiscount = discountField.getDefaultAttr();
                quotationDiscount.setUseLinkValue(BasicConstant.ONE);
                quotationDiscount.setLinkFormValue(getDoubleOrDefaultFromFormData(linkFormData, QuotationEnum.DISCOUNT.getAttr(), 0D));
                discountField.setDefaultAttr(quotationDiscount);
                // 合同金额设置默认值
                DefaultAttrPoJo otherExpense = otherExpenseField.getDefaultAttr();
                otherExpense.setUseLinkValue(BasicConstant.ONE);
                otherExpense.setLinkFormValue(getDoubleOrDefaultFromFormData(linkFormData, QuotationEnum.OTHER_EXPENSE.getAttr(), 0D));
                otherExpenseField.setDefaultAttr(otherExpense);
                // 合同优惠金额设置默认值
                DefaultAttrPoJo discountAmount = discountAmountField.getDefaultAttr();
                discountAmount.setUseLinkValue(BasicConstant.ONE);
                discountAmount.setLinkFormValue(getDoubleOrDefaultFromFormData(linkFormData, QuotationEnum.DISCOUNT_AMOUNT.getAttr(), 0D));
                discountAmountField.setDefaultAttr(discountAmount);
                // 合同产品总计设置默认值
                DefaultAttrPoJo productTotal = productTotalField.getDefaultAttr();
                productTotal.setUseLinkValue(BasicConstant.ONE);
                productTotal.setLinkFormValue(getDoubleOrDefaultFromFormData(linkFormData, QuotationEnum.PRODUCT_TOTAL.getAttr(), 0D));
                productTotalField.setDefaultAttr(productTotal);
                break;
            default:
                throw new XbbException(TemplateErrorCodeEnum.API_ERROR_350006);
        }
    }

   /* @Override
    public BusinessProductListVO getQuotationProductList(BusinessProductListDTO businessProductListDTO) throws XbbException {
        BusinessProductListVO businessProductListVO = new BusinessProductListVO();

        String corpid = businessProductListDTO.getCorpid();
        String userId = businessProductListDTO.getUserId();
        UserEntity userEntity = userModel.getByKey(userId, corpid);
        Boolean detailGet = businessProductListDTO.getDetailGet();
        Long quotationId = businessProductListDTO.getDataId();

        // 获取关联产品
        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, corpid);
        modelMap.put("quotationId", quotationId);
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        modelMap.put(ParameterConstant.PAGE,  businessProductListDTO.getPage());
        PageHelper pageHelper = PageHelperUtil.getPageHelper(modelMap, quotationProductModel, businessProductListDTO.getPageSize());
        List<QuotationProductEntity> quotationProducts = (List<QuotationProductEntity>) PageHelperUtil.getEntityList(modelMap, pageHelper, quotationProductModel);
        Map<String, FieldAttrEntity> explainMap = paasFormExplainService.getFieldAttrMapByBusinessType(businessProductListDTO.getBusinessType(), corpid);

        // 返回给前端的接受对象
        JSONObject productFinalObj = new JSONObject();

        // 总价格
        double totalPrice = 0D;
        boolean totalProductMoneyHide = false;
        JSONArray productLists = new JSONArray();
        for (QuotationProductEntity quotationProductEntity : quotationProducts) {
            JSONObject product = new JSONObject();
            product.put("parentId", quotationProductEntity.getParentId());
            product.put(StringConstant.SAAS_LINK_BUSINESS_ID, quotationProductEntity.getProductId());
            product.put(StringConstant.NUM,  quotationProductEntity.getProductNum());
            product.put(RelativeProductEnum.SALE_DISCOUNT.getSaasAttr(), quotationProductEntity.getDiscount());
            product.put(RelativeProductEnum.SALE_PRODUCT_PRICE.getSaasAttr(), quotationProductEntity.getPrice());
            product.put("estimateCost",quotationProductEntity.getCost());
            product.put(RelativeProductEnum.MEMO.getSaasAttr(),quotationProductEntity.getMemo());
            productLists.add(product);

            Double subTotal = Arith.mul(quotationProductEntity.getProductNum(), quotationProductEntity.getPrice());
            // 小计
            totalPrice = Arith.add(totalPrice, subTotal);
        }
        JSONObject productListObject = new JSONObject();
        productListObject.put(StringConstant.PRODUCT_LIST, productLists);
        productListObject.put(BusinessConstant.OTHERS, new JSONObject());
        JSONObject quotationDataList= new JSONObject();
        quotationDataList.put(QuotationEnum.PRODUCT.getAttr(), productListObject);
        quotationDataList.put("hidePrice", BasicConstant.ZERO);
        SaasAnalysisDataDTO saasAnalysis = new SaasAnalysisDataDTO();
        BeanUtil.copyProperties(businessProductListDTO, saasAnalysis);
        saasAnalysis.setForProcess(true);
        saasAnalysis.setBusinessType(XbbRefTypeEnum.QUOTATION.getCode());
        formatProduct4Show(quotationDataList, saasAnalysis);
        JSONObject quotationProductObj = quotationDataList.getJSONObject(QuotationEnum.PRODUCT.getAttr());
        JSONArray jsonArray = quotationProductObj.getJSONArray(StringConstant.PRODUCT_LIST);
        if (Objects.nonNull(quotationDataList.get("hidePrice"))) {
            totalProductMoneyHide = quotationDataList.getBoolean("hidePrice");
        }

        productFinalObj.put(StringConstant.PRODUCT_LIST, jsonArray);
        if (detailGet) {
            productFinalObj.put(BusinessConstant.EXPLAINS, saasGetHelp.getSelectProductExplains(XbbRefTypeEnum.QUOTATION, businessProductListDTO.getBusinessType(), corpid, QuotationEnum.PRODUCT.getAttr()));
        }
        businessProductListVO.setProduct(productFinalObj);

        // 产品价格总计
        JSONObject othersObj = new JSONObject();
        othersObj.put("unit", I18nMessageUtil.getMessage(CommonConstant.YUAN));
        String totalMoney = totalProductMoneyHide ? StringConstant.INVISIBLE_VALUE : attrDecimalPrecisionHelper.formatMoneyPrecision(totalPrice, explainMap, QuotationEnum.PRODUCT_TOTAL.getAttr());
        othersObj.put(BusinessConstant.TOTAL_PRODUCT_MONEY, totalMoney);
        productFinalObj.put(BusinessConstant.OTHERS, othersObj);
        businessProductListVO.setPageHelper(pageHelper);
        return businessProductListVO;
    }*/

    @Override
    public BaseVO changeStatus(ChangeStatusDTO changeStatusDTO) throws XbbException {
        if (!changeStatusDTO.getLoginUser().getPermSet().contains(ProPermissionAliasEnum.QUOTATION_UPDATE.getAlias())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100050, String.format(SystemErrorCodeEnum.API_ERROR_100050.getMsg(), ProPermissionAliasEnum.QUOTATION_UPDATE.getMemo()));
        }
        Long dataId = changeStatusDTO.getDataId();
        Integer businessType = changeStatusDTO.getBusinessType();
        String corpid = changeStatusDTO.getCorpid();
        String type = changeStatusDTO.getType();
        PaasFormDataEntityExt paasFormDataEntityExt = saasGetHelp.getFormData(dataId, corpid, businessType);
        if (paasFormDataEntityExt == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
        }
        PaasFormExplainEntity byBusinessType = paasFormExplainModel.getByBusinessType(businessType, corpid);
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(byBusinessType.getExplains(), QuotationEnum.STATUS.getAttr());
        JSONObject data = paasFormDataEntityExt.getData();
        String status = changeStatusDTO.getType();
        String oldStatus = FastJsonHelper.getStringOrDefaultFromFormData(data, QuotationEnum.STATUS.getAttr(), "");
        if (Objects.equals(oldStatus, status)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, ErrorMessageConstant.STATUS_NOT_MODIFIED);
        } else {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put(QuotationEnum.STATUS.getAttr(), status);
            UpdateDataEntity updateData = ExplainUtil.getUpdateData(dataId, jsonObject, corpid);
            quotationModel.updateBatch(Collections.singletonList(updateData), corpid);

            Runnable runnable = () -> {
                try {
                    // 报价单状态变更消息推送
                    FieldAttrEntity attrEntity = explainMap.get(QuotationEnum.STATUS.getAttr());
                    List<ItemPoJo> items = attrEntity.getItems();
                    String newStatus = "";
                    for (ItemPoJo itemPoJo : items){
                        if (Objects.equals(type, itemPoJo.getValue())) {
                            newStatus = itemPoJo.getText();
                        }
                    }

                    String quotationName = data.getString(QuotationEnum.NAME.getAttr());
                    List<String> quotationUserIdList = quotationUserModel.getQuotationUserIdList(corpid, dataId, null);
                    List<String> pushUserList = pushHelper.getUserIdListByPushSetRule(corpid, PushTypeEnum.QUOTATION_STATUS_PUSH.getCode(),
                            PushTypeEnum.QUOTATION_STATUS_PUSH.getSubCode(), changeStatusDTO.getLoginUser(), paasFormDataEntityExt);
                    pushUserList.addAll(quotationUserIdList);
                    //去除当前操作人，可能在上一行中加回来。。。
                    pushUserList.remove(changeStatusDTO.getUserId());
                    PushRefTypePojo.Options options = new PushRefTypePojo.Options(paasFormDataEntityExt.getAppId(), paasFormDataEntityExt.getMenuId(), paasFormDataEntityExt.getFormId(), dataId, Collections.singletonList(dataId), SaasMarkEnum.SAAS.getCode(), changeStatusDTO.getBusinessType(), changeStatusDTO.getBusinessType());
                    MessageRabbitMqDTO messageRabbitMqDTO = new MessageRabbitMqDTO(corpid, pushUserList, Collections.singletonList(dataId), 0, null, I18nMessageUtil.getMessage(QuotationPushConstant.QUOTATAION_CHANGE_TITLE), String.format(I18nMessageUtil.getMessage(QuotationPushConstant.QUOTATAION_CHANGE_CONTENT), changeStatusDTO.getLoginUserName(), quotationName, newStatus), null, options);
                    baseProducer.sendMessage(PushTypeEnum.QUOTATION_STATUS_PUSH, messageRabbitMqDTO);
                } catch (Exception e) {
                    LOG.error("报价单状态变更消息推送", e);
                }
            };
            threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);

            // 日志
            operationLogHelp.changeStatusLog(changeStatusDTO,paasFormDataEntityExt,updateData.getUpdateTime());
        }
        return new BaseVO();
    }

    @Override
    public void formatExportValue(List<PaasFormDataEntityExt> paasFormDataESList, FormDataListDTO formDataListDTO, List<FieldAttrEntityForImport> fieldAttrList) throws XbbException {
        List<Long> quotationIdIn = new ArrayList<>();
        paasFormDataESList.forEach(paasFormDataEntityExt -> quotationIdIn.add(paasFormDataEntityExt.getId()));
        List<QuotationProductEntity> quotationProductByContractIdIn = quotationProductModel.getQuotationProductByQuotationIdIn(formDataListDTO.getCorpid(), quotationIdIn);
        Map<Long, List<QuotationProductEntity>> productMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> productIdIn = new ArrayList<>();
        quotationProductByContractIdIn.forEach(quotationProductEntity -> {
            List<QuotationProductEntity> productEntityList = new ArrayList<>();
            if (productMap.containsKey(quotationProductEntity.getQuotationId())) {
                productEntityList.addAll(productMap.get(quotationProductEntity.getQuotationId()));
            }
            productEntityList.add(quotationProductEntity);
            productMap.put(quotationProductEntity.getQuotationId(), productEntityList);
            productIdIn.add(quotationProductEntity.getProductId());
        });
        HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
        BeanUtil.copyProperties(formDataListDTO, handlerExplainDTO);
        List<ProductEntityExt> productList = productModel.getProductListByIdIn(formDataListDTO.getCorpid(), productIdIn, 0);
        Map<Long, ProductEntityExt> productsMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        productList.forEach(item -> productsMap.put(item.getId(), item));

        Map<String, MultiUnitItemPoJo> groupBaseUnitStringMap = relativeProductHelp.getGroupBaseUnitStringMap(formDataListDTO.getCorpid());

        for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataESList) {
            JSONObject data = paasFormDataEntityExt.getData();
            data.put(QuotationEnum.GROSS_PROFIT_RATE.getAttr(), commonHelp.getPercentFormat(saasUpdateHelp.getDoubleIgnoreExceptionFormData(data, QuotationEnum.GROSS_PROFIT_RATE.getAttr(), 0D), 3, 2));
            data.put(QuotationEnum.DISCOUNT.getAttr(), commonHelp.getPercentFormat(saasUpdateHelp.getDoubleIgnoreExceptionFormData(data, QuotationEnum.DISCOUNT.getAttr(), 0D), 3, 2));
            List<QuotationProductEntity> singleContractProductEntityList = productMap.getOrDefault(paasFormDataEntityExt.getId(), new ArrayList<>());
            JSONArray productArray = new JSONArray();
            for (QuotationProductEntity entity : singleContractProductEntityList) {
                if (Objects.nonNull(entity.getPriceData()) && entity.getPriceData().size() > 0 ){
                    entity.getData().putAll(entity.getPriceData());
                }
                JSONObject productItemObj = new JSONObject();
                if (Objects.nonNull(entity.getData())) {
                    productItemObj.putAll(entity.getData());
                }
                ProductEntityExt productEntityExt = productsMap.getOrDefault(entity.getProductId(), new ProductEntityExt());
                JSONObject productData = productEntityExt.getData();
                if (productData != null) {
                    productItemObj.put(SelectProductEnum.UNIT.getAttr(), productData.get(ProductEnum.UNIT.getAttr()));
                    productItemObj.put(ProductEnum.ENABLE_MULTI_UNIT.getAttr(), productData.getIntValue(ProductEnum.ENABLE_MULTI_UNIT.getAttr()));
                    productItemObj.put(SelectProductEnum.BARCODE.getAttr(), productData.get(ProductEnum.BARCODE.getAttr()));
                }
                productItemObj.put(SelectProductEnum.PRODUCT_NAME.getAttr(), entity.getProductName());
                productItemObj.put(SelectProductEnum.PRODUCT_NO.getAttr(), entity.getProductNo());
                productItemObj.put(SelectProductEnum.SPECIFICATION.getAttr(), entity.getSpecification());
                if (Objects.nonNull(entity.getPriceData()) && entity.getPriceData().size() > 0){
                    productItemObj.put(QuotationProductEnum.SELLING_PRICE.getAttr(), entity.getData().get(QuotationProductEnum.SELLING_PRICE.getAttr()));
                    productItemObj.put(QuotationProductEnum.SUBTOTAL.getAttr(), Arith.mul(entity.getData().getDouble(SelectProductEnum.SELLING_PRICE.getAttr()), entity.getBusinessNum()));
                }else {
                    productItemObj.put(QuotationProductEnum.SELLING_PRICE.getAttr(), entity.getPrice());
                    productItemObj.put(QuotationProductEnum.SUBTOTAL.getAttr(), Arith.mul(entity.getPrice(), entity.getProductNum()));
                }
                productItemObj.put(QuotationProductEnum.DISCOUNT.getAttr(), entity.getDiscount());
                productItemObj.put(QuotationProductEnum.NUM.getAttr(), entity.getProductNum());
                productItemObj.put(QuotationProductEnum.MEMO.getAttr(), entity.getMemo());
                //基本单位时直接塞入productUnit
                if (Objects.isNull(entity.getBusinessUnit())){
                    if (Objects.equals(productItemObj.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr()), BasicConstant.ONE)){
                        productItemObj.put(ProductEnum.UNIT.getAttr(), groupBaseUnitStringMap.getOrDefault(productItemObj.getString(ProductEnum.UNIT.getAttr()), new MultiUnitItemPoJo()).getBaseValue());
                        entity.setProductUnit(productItemObj.getString(ProductEnum.UNIT.getAttr()));
                    }
                    productItemObj.put(SelectProductEnum.NUM.getAttr(), entity.getProductNum());
                }else {
                    productItemObj.put(ProductEnum.UNIT.getAttr(), entity.getBusinessUnit());
                    productItemObj.put(SelectProductEnum.NUM.getAttr(), entity.getBusinessNum());
                }
                if(Objects.equals(productItemObj.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr()), BasicConstant.ONE)){
                    productItemObj.put(SelectProductEnum.BASIC_UNIT.getAttr(), entity.getProductUnit());
                    productItemObj.put(SelectProductEnum.BASIC_UNIT_NUM.getAttr(),  entity.getProductNum());
                }else {
                    productItemObj.put(SelectProductEnum.BASIC_UNIT.getAttr(), "");
                    productItemObj.put(SelectProductEnum.BASIC_UNIT_NUM.getAttr(), "");
                }
                productArray.add(productItemObj);
            }
            data.put(QuotationEnum.PRODUCT.getAttr(), productArray);
        }
    }

    @Override
    public FormDataAddDTO formatExcelValue(ImportFormDataDTO importFormDataDTO, List<CellTitlePojo> titlePojoList, RowGroupPojo rowGroupPojo, List<FieldAttrEntityForImport> fieldAttrList) throws XbbException {
        FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
        BeanUtil.copyProperties(importFormDataDTO, formDataAddDTO);
        formDataAddDTO.setSerialNo("");
        JSONObject dataJson = new JSONObject();
        List<List<CellValuePojo>> rowValueList = rowGroupPojo.getRowValueList();
        // 分组的第一条数据作为给实体对象赋值的数据
        List<CellValuePojo> cellValueList = rowValueList.get(0);

        Long linkCustomerId = 0L;
        String version = "";
        String groupNumber = "";
        ReturnUserAndDepartmentPojo returnUserAndDepartmentPojo = new ReturnUserAndDepartmentPojo();
        String corpid = importFormDataDTO.getCorpid();

        FieldAttrEntityForImport linkCustomerIdAttr = null;
        for (FieldAttrEntityForImport fieldAttrEntityForImport : fieldAttrList) {
            if (Objects.equals(fieldAttrEntityForImport.getAttr(), QuotationEnum.CUSTOMER_ID.getAttr())) {
                linkCustomerIdAttr = fieldAttrEntityForImport;
                break;
            }
        }

        if (Objects.nonNull(linkCustomerIdAttr)) {
            linkCustomerId = importHelper.formatLinkCustomer2CustomerId(titlePojoList, dataJson, rowValueList, linkCustomerIdAttr);
        }

        for (FieldAttrEntityForImport fieldAttr : fieldAttrList) {
            String attr = fieldAttr.getAttr();
            Integer fieldType = fieldAttr.getFieldType();
            String attrName = fieldAttr.getAttrName();
            Integer columnIndex = importHelper.getColumnIndexByTitle(titlePojoList, attrName, null);
            Object cellValue = importHelper.getValueByColumnIndex(cellValueList, columnIndex);
            if (Objects.equals(attr, QuotationEnum.PRODUCT.getAttr())) {
                importHelper.formatCommonProduct(titlePojoList, dataJson, rowValueList, fieldAttr, XbbRefTypeEnum.QUOTATION.getCode(), corpid);
            } else if (Objects.equals(attr, QuotationEnum.CUSTOMER_ID.getAttr())) {

            } else if (Objects.equals(fieldType, FieldTypeEnum.SUB_FORM.getType())) {
                importHelper.formatSubFormValue4Import(rowValueList, titlePojoList, importFormDataDTO, fieldAttr, dataJson);
            } else {
                if (Objects.isNull(cellValue) || StringUtil.isEmpty(cellValue.toString())) {
                    continue;
                }
                // 报价人特殊处理
                if (Objects.equals(attr, QuotationEnum.QUOTATION_PERSON.getAttr())) {
                    Map<String, Object> linkBusinessMap = fieldAttr.getLinkBusinessMap();
                    if (linkBusinessMap.containsKey(cellValue.toString())) {
                        returnUserAndDepartmentPojo.setId(linkBusinessMap.get(cellValue.toString()));
                    } else {
                        // 报价人错误数据id用-1
                        if (Objects.equals(importFormDataDTO.getIsNoSignImport(), 1)) {
                            returnUserAndDepartmentPojo.setId(StringConstant.NOT_IN_SYSTEM_ID);
                            returnUserAndDepartmentPojo.setName(cellValue.toString());
                        } else {
                            throw new XbbException(QuotationErrorCodeEnum.API_ERROR_246002);
                        }
                    }
                    dataJson.put(attr, JSON.toJSON(returnUserAndDepartmentPojo));
                } else if (ImportHelper.commonHandleFieldType.contains(fieldAttr.getFieldType())) {
                    importHelper.formatCommonField(dataJson, fieldAttr, cellValue);
                } else {
                    if (Objects.equals(attr, QuotationEnum.CONTACT_ID.getAttr())) {
                        importHelper.formatRelyBusiness(linkCustomerId, dataJson, fieldAttr, cellValue, ContactEnum.CUSTOMER_NAME.getAttr());
                    } else if (Objects.equals(attr, QuotationEnum.OPPORTUNITY_ID.getAttr())) {
                        importHelper.formatRelyBusiness(linkCustomerId, dataJson, fieldAttr, cellValue, SalesOpportunityEnum.CUSTOMER_NAME.getAttr());
                    } else if (Objects.equals(attr, QuotationEnum.VERSION.getAttr())) {
                        version = cellValue.toString();
                        dataJson.put(attr, version);
                    } else if (Objects.equals(attr, QuotationEnum.GROUP_NUMBER.getAttr())) {
                        groupNumber = cellValue.toString();
                        dataJson.put(attr, groupNumber);
                    } else if (Objects.equals(attr, QuotationEnum.DISCOUNT.getAttr())) {
                        //导入的时候是百分比的情况时候，转为数字
                        if (!RegexUtil.isNumber(cellValue.toString())) {
                            cellValue  = ((String) cellValue).substring(0,((String) cellValue).length() - 1);
                            cellValue = Double.parseDouble(cellValue.toString()) / 100;
                        }
                        dataJson.put(attr, Double.parseDouble(cellValue.toString()));
                    } else if (Objects.equals(fieldType, FieldTypeEnum.LINK_DATA.getType())) {
                        importHelper.formatLinkData(cellValue, fieldAttr, dataJson);
                    } else if (Objects.equals(fieldType, FieldTypeEnum.LINK_DATA_MULTI.getType())) {
                        importHelper.formatLinkDataMulti(cellValue, importFormDataDTO, fieldAttr, dataJson);
                    } else {
                        dataJson.put(attr, cellValue);
                    }
                }
            }
        }
        //报价单骚逻辑，不直接存报价单编号，而是通过版本和组号拼接
        String serialNo = "";
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(groupNumber);
        //版本号正整数的情况下，给他补成.0结尾的格式
        if (version.matches(RegExConstant.QUOTATION_INTFER)) {
            StringBuilder stringBuilder1 = new StringBuilder();
            stringBuilder1.append(version);
            stringBuilder1.append(".0");
            version = stringBuilder1.toString();
        }
        stringBuilder.append(version);
        serialNo = stringBuilder.toString();
        formDataAddDTO.setSerialNo(serialNo);
        formDataAddDTO.setDataList(dataJson);
        return formDataAddDTO;
    }

    @Override
    public DefaultDataVO getQuotationDefault(DefaultDataDTO businessDataDTO, Map<String, FieldAttrEntity> explainMap, PaasFormDataEntityExt quotationEntity) throws XbbException{
        DefaultDataVO defaultDataVO = new DefaultDataVO();
        List<DefaultDataPojo> defaultData = new ArrayList<>();
        String corpid = businessDataDTO.getCorpid();
        Long quotationId = quotationEntity.getId();
        JSONObject quotationData = quotationEntity.getData();
        // 获取关联产品
        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, corpid);
        modelMap.put("quotationId", quotationId);
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        List<QuotationProductEntity> quotationProducts = quotationProductModel.getProductsByQuoId(quotationId, corpid);

        JSONObject productListObj = new JSONObject();
        JSONArray productList = new JSONArray();
        for (QuotationProductEntity quotationProductEntity : quotationProducts) {
            JSONObject product = new JSONObject();
            product.put("parentId", quotationProductEntity.getParentId());
            product.put(StringConstant.SAAS_LINK_BUSINESS_ID, quotationProductEntity.getProductId());
            product.put(StringConstant.NUM,  quotationProductEntity.getProductNum());
            product.put(RelativeProductEnum.SALE_DISCOUNT.getSaasAttr(), quotationProductEntity.getDiscount());
            product.put(RelativeProductEnum.SALE_PRODUCT_PRICE.getSaasAttr(), quotationProductEntity.getPrice());
            product.put("estimateCost",quotationProductEntity.getCost());
            product.put(RelativeProductEnum.MEMO.getSaasAttr(),quotationProductEntity.getMemo());
            productList.add(product);
        }
        productListObj.put(StringConstant.PRODUCT_LIST, productList);
        productListObj.put(BusinessConstant.OTHERS, new JSONObject());
        JSONObject contractDataList= new JSONObject();
        contractDataList.put(ContractEnum.PRODUCT.getAttr(), productListObj);
        SaasAnalysisDataDTO saasAnalysisDataDTO = new SaasAnalysisDataDTO();
        saasAnalysisDataDTO.setForProcess(true);
        saasAnalysisDataDTO.setBusinessType(XbbRefTypeEnum.CONTRACT.getCode());
        BeanUtil.copyProperties(businessDataDTO, saasAnalysisDataDTO);
        contractService.formatProduct4Show(contractDataList, saasAnalysisDataDTO);
        JSONObject products = contractDataList.getJSONObject(ContractEnum.PRODUCT.getAttr());
        JSONArray productArr = products.getJSONArray(StringConstant.PRODUCT_LIST);

        // 默认产品
        DefaultDataPojo productDefault = new DefaultDataPojo();
        List<Object> defaultProducts = new ArrayList<>();
        defaultProducts.addAll(productArr);
        productDefault.setValue(defaultProducts);
        productDefault.setAttr(ContractEnum.PRODUCT.getAttr());
        defaultData.add(productDefault);



        Double productTotal = quotationData.getDouble(QuotationEnum.PRODUCT_TOTAL.getAttr());
        if (productTotal != null) {
            DefaultDataPojo productTotalDefault = commonHelp.setDefaultData(ContractEnum.PRODUCT_TOTAL.getAttr(), Collections.singletonList(productTotal));
            defaultData.add(productTotalDefault);
        }

        Double discount = quotationData.getDouble(QuotationEnum.DISCOUNT.getAttr());
        if (discount != null) {
            DefaultDataPojo discountDefault = commonHelp.setDefaultData(ContractEnum.DISCOUNT.getAttr(), Collections.singletonList(discount));
            defaultData.add(discountDefault);
        }

        Double otherExpense = quotationData.getDouble(QuotationEnum.OTHER_EXPENSE.getAttr());
        if (otherExpense != null) {
            DefaultDataPojo otherExpenseDefault = commonHelp.setDefaultData(ContractEnum.OTHER_EXPENSE.getAttr(), Collections.singletonList(otherExpense));
            defaultData.add(otherExpenseDefault);
        }

        Double discountAmount = quotationData.getDouble(QuotationEnum.DISCOUNT_AMOUNT.getAttr());
        if (discountAmount != null) {
            DefaultDataPojo discountAmountDefault = commonHelp.setDefaultData(ContractEnum.DISCOUNT_AMOUNT.getAttr(), Collections.singletonList(discountAmount));
            defaultData.add(discountAmountDefault);
        }

        Double amount = quotationData.getDouble(QuotationEnum.AMOUNT.getAttr());
        if (amount != null) {
            DefaultDataPojo amountDefault = commonHelp.setDefaultData(ContractEnum.AMOUNT.getAttr(), Collections.singletonList(amount));
            defaultData.add(amountDefault);
        }
        defaultDataVO.setDefaultData(defaultData);
        return defaultDataVO;
    }

    @Override
    public Set<Long> customerQuotation(String corpid, Long customerId, Long startTime, Long endTime) throws XbbException {
        //需要查出的字段
        List<String> quotationFields = Collections.singletonList("dataId");
        List<PaasFormDataEntity> allQuotationList = customerQuoataionList(corpid, customerId, quotationFields, startTime, endTime);
        //包装quotationIdSet
        Set<Long> quotationIdSet = new HashSet<>();
        for (PaasFormDataEntity entity : allQuotationList) {
            Long quotationId = entity.getDataId();
            quotationIdSet.add(quotationId);
        }
        return quotationIdSet;
    }

    @Override
    public List<PaasFormDataEntity> customerQuotationTrend(String corpid, Long customerId, Long startTime, Long endTime) throws XbbException {
        //需要查出的字段
        String numberData = QuotationEnum.QUOTATION_NO.getAttr();
        String quotationTimeData = QuotationEnum.getAttrConnectData(QuotationEnum.QUOTATION_TIME);
        String amountData = QuotationEnum.getAttrConnectData(QuotationEnum.AMOUNT);
        List<String> quotationFields = Arrays.asList("dataId", numberData, quotationTimeData, amountData);
        return customerQuoataionList(corpid, customerId, quotationFields, startTime, endTime);
    }
    /**
     * 单个客户相关的报价单
     *
     * @param corpid 公司id
     * @param customerId 客户id
     * @param quotationFields 需要获得的字段
     * @return java.util.List<com.xbongbong.paas.domain.entity.PaasFormDataEntity>
     * @throws XbbException findByPage会出现异常
     * @author 徐俊杰
     * @date 2019/8/30 13:34
     * @since v1.0
     */
    private List<PaasFormDataEntity> customerQuoataionList(String corpid, Long customerId, List<String> quotationFields, Long startTime, Long endTime) throws XbbException {
        //基本入参
        Integer del = DelEnum.NORMAL.getDel();
        //查询信息
        BoolQueryBuilder quotationQuery = boolQuery();
        quotationQuery.filter(termQuery("corpid.keyword", corpid));
        quotationQuery.filter(termQuery("del", del));
        String customerIdField = QuotationEnum.getEsAttr4Keyword(QuotationEnum.CUSTOMER_ID);
        quotationQuery.filter(termQuery(customerIdField, customerId));
        quotationQuery.filter(termQuery(QuotationEnum.getEsAttr4Keyword(QuotationEnum.IS_NEW), 1));
        quotationQuery.filter(termsQuery("flowStatus", FlowStatusEnum.getStatisticType()));
        if (startTime != null && endTime != null) {
            String fieldTime = QuotationEnum.getEsAttr4Keyword(QuotationEnum.QUOTATION_TIME);
            quotationQuery.filter(rangeQuery(fieldTime).gte(startTime).lt(endTime));
        }
        List<SortBuilder> sortBuilderList = Collections.singletonList(new FieldSortBuilder(QuotationEnum.getAttrConnectData(QuotationEnum.QUOTATION_TIME)).order(SortOrder.DESC));
        //模拟分页查询
        List<PaasFormDataEntity> allQuotationList = new ArrayList<>();
        for (int quotationPage = 0, quotationPageSize = 500; ; quotationPage++) {
            XbbAggregatedPage<PaasFormDataEntity> quotationEntities = esHelper.findByPage(IndexTypeEnum.IDX_SAAS_QUOTATION, quotationQuery, PaasFormDataEntity.class, quotationFields, quotationPage, quotationPageSize, sortBuilderList);
            List<PaasFormDataEntity> quotationList = quotationEntities.getContent();
            allQuotationList.addAll(quotationList);
            if (quotationList.size() < 500) {
                break;
            }
        }
        return allQuotationList;
    }

    /**
     * 项目日志
     *
     * @param saasFormSaveDTO 参数
     * @param creatorId 创建人id
     * @param newCustomerId 客户id
     * @param communicateMemo 备注
     * @param subType 日志类型
     * @param log 日志
     * @author 徐俊杰
     * @date 2019/8/27 14:04
     * @since v1.0
     */
    // private void projectLog(SaasFormSaveDTO saasFormSaveDTO, String creatorId, Long newCustomerId, String communicateMemo, Integer subType, String log) {
    //     PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
    //     JSONObject newData = saasFormSaveDTO.getNewData();
    //     String corpid = newPaasFormDataEntity.getCorpid();
    //     Long quotationId = newPaasFormDataEntity.getId();
    //     //拼装
    //     try {
    //         CustomerDynamicAddDTO customerDynamicAddDTO = new CustomerDynamicAddDTO();
    //         String customerName = newData.getString(QuotationEnum.CUSTOMER_NAME.getAttr());
    //         customerDynamicAddDTO.setCorpid(corpid);
    //         customerDynamicAddDTO.setUserId(creatorId);
    //         customerDynamicAddDTO.setCustomerId(newCustomerId);
    //         customerDynamicAddDTO.setCustomerName(customerName);
    //         customerDynamicAddDTO.setMemo(communicateMemo);
    //         customerDynamicAddDTO.setCommunicateBusinessText(newPaasFormDataEntity.getSerialNo());
    //         customerDynamicAddDTO.setCommunicateBusinessType(XbbRefTypeEnum.QUOTATION.getCode());
    //         customerDynamicAddDTO.setDataId(quotationId);
    //         customerDynamicAddDTO.setLogType(subType);
    //         customerCommunicateService.addCustomerDynamic(customerDynamicAddDTO);
    //     } catch (Exception e) {
    //         LOG.error(log, e);
    //     }
    // }

    @Override
    public List<PaasFormDataEntityExt> getQuotationEsDataListByCustomerId(String corpid, Long customerId) throws XbbException {
        return quotationModel.getQuotationListByLinkId(corpid, customerId, QuotationEnum.CUSTOMER_ID, PaasFormDataEntityExt.class);
    }

    @Override
    public ProductSummaryVO summaryProductList(BusinessProductListDTO businessProductListDTO) throws XbbException {
        // 获取参数
        String corpid = businessProductListDTO.getCorpid();
        Long dataId = businessProductListDTO.getDataId();
        // PaasFormDataEntityExt quotation = proFormHelp.get(dataId, corpid, XbbRefTypeEnum.QUOTATION.getCode());
        PaasFormDataEntityExt quotation = proGetHelp.getByKey(dataId, businessProductListDTO.getBusinessType(), businessProductListDTO.getSaasMark(), corpid);

        if (Objects.isNull(quotation)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
        }
        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, corpid);
        modelMap.put(ParameterConstant.QUOTATION_ID, dataId);
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        modelMap.put("columns", "product_num, price, business_num,price_data");
        List<QuotationProductEntity> quotationProductEntities = quotationProductModel.findEntitys(modelMap);

        PaasFormExplainEntity opportunityExplain = paasFormExplainModel.getByFormId(quotation.getFormId(), corpid);
        if (Objects.isNull(opportunityExplain)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(opportunityExplain.getExplains());
        Boolean hidePrice = false;
        // 关联产品字段
        FieldAttrEntity productField = explainMap.get(SalesOpportunityEnum.PRODUCTS.getAttr());
        FieldAttrEntity productTotalField = new FieldAttrEntity();
        if (Objects.nonNull(productField)) {
            Map<Integer, List<UserTeamEntity>> userTeamMap = userTeamService.getUserTeam(dataId, corpid, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode());
            List<String> ownerIds = new ArrayList<>();
            List<String> coUserIds = new ArrayList<>();
            for (Map.Entry<Integer, List<UserTeamEntity>> entry : userTeamMap.entrySet()) {
                if (Objects.equals(entry.getKey(), BasicConstant.MAIN_USER)) {
                    entry.getValue().forEach(team -> ownerIds.add(team.getUserId()));
                } else if (Objects.equals(entry.getKey(), BasicConstant.COOP_USER)) {
                    entry.getValue().forEach(team -> coUserIds.add(team.getUserId()));
                }
            }
            HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
            BeanUtil.copyProperties(businessProductListDTO, handlerExplainDTO);
            handlerExplainDTO.setOwnerId(ownerIds);
            handlerExplainDTO.setCoUserId(coUserIds);
            handlerExplainDTO.setCreatorId(quotation.getCreatorId());
            SubFormPoJo subForm = productField.getSubForm();
            List<FieldAttrEntity> fieldAttrEntityList = new ArrayList<>();
            if (Objects.nonNull(subForm.getItems())) {
                fieldAttrEntityList = (List<FieldAttrEntity>) subForm.getItems();
            }
            for (FieldAttrEntity fieldAttrEntity : fieldAttrEntityList) {
                if (Objects.equals(fieldAttrEntity.getAttr(), OpportunityProductEnum.SELLING_PRICE.getAttr())) {
                    productTotalField = fieldAttrEntity;
                    if (ExplainUtil.isFieldNeedHide(fieldAttrEntity, handlerExplainDTO)) {
                        hidePrice = true;
                    }
                }
            }
        }


        ProductSummaryVO businessProductListVO = new ProductSummaryVO();

        Double num = 0D;
        Double count = 0D;
        for (QuotationProductEntity productEntity : quotationProductEntities) {
            Double productNum = productEntity.getProductNum() != null ? productEntity.getProductNum(): 0D;
            Double price = productEntity.getPrice() == null ? 0D : productEntity.getPrice();
            if (Objects.nonNull(productEntity.getPriceData()) && !productEntity.getPriceData().isEmpty()) {
                count = Arith.add(count, Arith.mul(productEntity.getBusinessNum(), productEntity.getPriceData().getDouble(SelectProductEnum.SELLING_PRICE.getAttr())));
            } else {
                count = Arith.add(count, Arith.mul(productNum, price));
            }
            num = Arith.add(num, Objects.nonNull(productEntity.getBusinessNum()) ? productEntity.getBusinessNum() : productNum);
        }
        JSONObject others = new JSONObject();
        others.put("hidePrice", hidePrice);
        others.put("amount", count);
        businessProductListVO.setOthers(others);
        Integer productSize = quotationProductEntities.size();
        String summaryInfo = String.format(I18nMessageUtil.getMessage(StringConstant.PRODUCTS_TYPE_NUM), productSize, Arith.doubleToBigDecimal(num));
        businessProductListVO.setSummaryInfo(summaryInfo);
        businessProductListVO.setMoneyInfo(String.format(I18nMessageUtil.getMessage(StringConstant.PRODUCTS_MONEY_COUNT), I18nMessageUtil.getMessage(I18nStringConstant.QUOTE), count));
        return businessProductListVO;
    }

    @Override
    public void dataConsistencyUpdate(String corpid, Long linkId, String linkName, String linkAttr, String linkNameAttr) throws XbbException {
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0 ))
                    .filter(termQuery("data." + linkAttr + ".keyword", linkId));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_QUOTATION, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", ids);
            param.put("del", 0);
            List<QuotationEntityExt> quotationEntityExts = quotationModel.findEntitys(param);

            if (Objects.nonNull(quotationEntityExts) && !quotationEntityExts.isEmpty()) {
                List<QuotationUpdateDTO> quotationUpdateDTOList = new ArrayList<>();
                for (QuotationEntityExt entityExt : quotationEntityExts) {
                    QuotationUpdateDTO quotationUpdateDTO = new QuotationUpdateDTO();
                    quotationUpdateDTO.setId(entityExt.getId());
                    JSONObject data = new JSONObject();
                    data.put(linkNameAttr, linkName);
                    quotationUpdateDTO.setData(data);
                    quotationUpdateDTOList.add(quotationUpdateDTO);
                }
                QuotationUpdateBatchDTO contractUpdateBatchDTO = new QuotationUpdateBatchDTO();
                contractUpdateBatchDTO.setCorpid(corpid);
                contractUpdateBatchDTO.setQuotationUpdateDTOList(quotationUpdateDTOList);
                updateBatch(contractUpdateBatchDTO);
            }

        } catch (Exception e) {
            LOG.error("QuotationServiceImpl.dataConsistencyUpdate 出错， corpid=" + corpid + " linkId=" + linkId + " linkName=" + linkName + " linkAttr=" + linkAttr + " linkNameAttr=" + linkNameAttr, e);
        }
    }

    @Override
    public BaseVO updateBatch(QuotationUpdateBatchDTO quotationUpdateBatchDTO) throws XbbException {
        BaseVO baseVO = new BaseVO();
        try {
            String corpid = quotationUpdateBatchDTO.getCorpid();
            List<UpdateDataEntity> updateList = new ArrayList<>();
            List<QuotationUpdateDTO> quotationUpdateDTOList = quotationUpdateBatchDTO.getQuotationUpdateDTOList();
            if (Objects.nonNull(quotationUpdateDTOList) && !quotationUpdateDTOList.isEmpty()) {
                quotationUpdateDTOList.forEach((item)->{
                    updateList.add(ExplainUtil.getUpdateData(item.getId(), item.getData(), corpid));
                });
            }
            if (!updateList.isEmpty()) {
                quotationModel.updateBatch(updateList, corpid);
            }
        } catch (Exception e) {
            LOG.error("quotationServiceImpl.updateBatch 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return baseVO;
    }

    @Override
    public void updateRollback(List<Long> idIn, String corpid) throws XbbException {
        if (Objects.isNull(idIn) || idIn.isEmpty()) {
            return;
        }
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("idIn", idIn);
        param.put(StringConstant.CORPID, corpid);
        List<QuotationEntityExt> quotationList = quotationModel.findEntitysWithoutSub(param);
        if (Objects.nonNull(quotationList)) {
            for (QuotationEntityExt item : quotationList) {
                PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
                BeanUtil.copyProperties(item, paasFormDataEntity);
                proEsHelper.reductionEsInUpdate(paasFormDataEntity, item.getId(), corpid, IndexTypeEnum.IDX_SAAS_QUOTATION);
            }
        }
    }

    @Override
    public void restoreBatch(String corpid, Map<Long, Long> customerUpdateTimeMap, CustomerRestoreBatchDTO customerRestoreBatchDTO) throws XbbException {
        try {
            // 根据客户的 id 和 updateTime 来查询要还原的数据
            List<Long> dataIdList = new ArrayList<>();
            List<String> quotationNames = new ArrayList<>();
            BoolQueryBuilder booleanQuery = boolQuery();
            booleanQuery.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, corpid));
            booleanQuery.filter(termQuery(StringConstant.DEL, DelEnum.DELETE.getDel()));
            for (Map.Entry<Long, Long> entry : customerUpdateTimeMap.entrySet()) {
                BoolQueryBuilder shouldQueryBuilder = boolQuery();
                shouldQueryBuilder.filter(termsQuery(QuotationEnum.getEsAttr4Keyword(QuotationEnum.CUSTOMER_ID), entry.getKey().toString()));
                shouldQueryBuilder.filter(rangeQuery(QuotationEnum.UPDATE_TIME.getAttr()).gte(entry.getValue()));
                booleanQuery.should(shouldQueryBuilder);
            }
            booleanQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
            List<String> fieldList = new ArrayList<>();
            fieldList.add(StringConstant.SAAS_LINK_BUSINESS_ID);
            fieldList.add(BasicConstant.SERIAL_NO);
            fieldList.add(SalesOpportunityEnum.getAttrConnectData(SalesOpportunityEnum.NAME));
            List<PaasFormDataEntityExt> paasFormDataEntityExtList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_QUOTATION, booleanQuery, PaasFormDataEntityExt.class, fieldList);
            paasFormDataEntityExtList.forEach(item -> {
                dataIdList.add(item.getId());
                quotationNames.add(item.getSerialNo() + "（" + item.getData().getString(QuotationEnum.NAME.getAttr()) + "）");
            });
            if (dataIdList.isEmpty()) {
                return;
            }
            quotationModel.restoreBatch(dataIdList, corpid, DelEnum.NORMAL.getDel());

            // 日志
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.REVERT_CANCEL;
            String nameStr = org.apache.commons.lang3.StringUtils.join(quotationNames, "，");
            String userName = customerRestoreBatchDTO.getLoginUserName();
            String userId = customerRestoreBatchDTO.getUserId();
            if(dataIdList.size() > 1){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_ARCHIVE_FORM_DATA), userName, operateTypeEnum.getName(), nameStr);
                List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                InfoArrPojo infoArrPojo = new InfoArrPojo();
                infoArrPojo.setTitle(XbbRefTypeEnum.QUOTATION.getName());
                infoArrPojo.setContent(nameStr);
                infoArrPojoList.add(infoArrPojo);
                mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, userName, OperateModuleTypeEnum.QUOTATION, operateTypeEnum,
                        "", "", memo, customerRestoreBatchDTO.getHttpHeader());
            } else if(Objects.equals(dataIdList.size(), 1)){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_ARCHIVE_FORM_DATA), userName, operateTypeEnum.getName(), nameStr);
                mongoLogHelp.buildLog(corpid, userId, userName, OperateModuleTypeEnum.QUOTATION, operateTypeEnum,
                        dataIdList.get(0).toString(), nameStr, memo, customerRestoreBatchDTO.getHttpHeader());
            }
        } catch (Exception e){
            LOG.error("QuotationServiceImpl.restoreBatch 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }


    /**
     * 批量编辑
     *
     * @param quotationEditAttrUpdateDTO
     * @return BaseVO
     * @throws XbbException 业务异常
     * @author long.rao
     * @date 2019-10-17 10:02
     */
    @Override
    public BaseVO batchEditAttr(QuotationEditAttrUpdateDTO quotationEditAttrUpdateDTO) throws XbbException {
        try {
            String userId = quotationEditAttrUpdateDTO.getUserId();
            String loginUserName = quotationEditAttrUpdateDTO.getLoginUserName();
            Integer fieldType = quotationEditAttrUpdateDTO.getFieldType();
            Integer isBatch = quotationEditAttrUpdateDTO.getIsBatch();
            Integer saasMark = quotationEditAttrUpdateDTO.getSaasMark();
            Long formId = quotationEditAttrUpdateDTO.getFormId();
            List<Long> idIn = quotationEditAttrUpdateDTO.getDataIdList();
            List<QuotationUpdateDTO> quotationUpdateDTOS = new ArrayList<>();
            String corpid = quotationEditAttrUpdateDTO.getCorpid();
            Integer businessType = quotationEditAttrUpdateDTO.getBusinessType();
            Boolean isFieldDependence = quotationEditAttrUpdateDTO.getIsFieldDependence();
            idIn.forEach((item)->{
                QuotationUpdateDTO quotationUpdateDTO = new QuotationUpdateDTO();
                quotationUpdateDTO.setId(item);
                JSONObject data = ProSaveHelp.getBatchUpdateData(quotationEditAttrUpdateDTO.getFieldEditedList());
                quotationUpdateDTO.setData(data);
                quotationUpdateDTOS.add(quotationUpdateDTO);
            });
            List<QuotationEntityExt> quotationEntityExts = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", quotationEditAttrUpdateDTO.getDataIdList());
            if (!quotationUpdateDTOS.isEmpty()) {
                quotationEntityExts = quotationModel.findEntitys(param);
                if (Objects.isNull(quotationEntityExts)){
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
                }
                //权限团队校验前置了
                List<Long> errorIdList = new ArrayList<>();
//                List<Long> errorIdList = userTeamHelp.batchTeamMembersCheckEditPermission(quotationEditAttrUpdateDTO.getBusinessType(), quotationEditAttrUpdateDTO.getSaasMark(),
//                        quotationEditAttrUpdateDTO.getMenuId(), quotationEditAttrUpdateDTO.getLoginUser(), quotationEditAttrUpdateDTO.getDistributorMark(),
//                        quotationEditAttrUpdateDTO.getDataIdList(), new HashMap<>());
                List<String> errorNameList = new ArrayList<>();
                for (QuotationEntityExt quotationEntityExt : quotationEntityExts) {
                    if (errorIdList.contains(quotationEntityExt.getId())) {
                        errorNameList.add(quotationEntityExt.getSerialNo());
                    }
                }
                String nameStr = StringUtils.join(errorNameList, "、");
                if (CollectionUtils.isNotEmpty(errorNameList)) {
                    throw new XbbException(UserTeamErrorCodeEnum.API_ERROR_271038.getCode(), String.format(UserTeamErrorCodeEnum.API_ERROR_271038.getMsg(), nameStr));
                }

                AttrValuePojo singleAttrValuePojo = ProSaveHelp.getSingleAttrValuePojo(isFieldDependence, quotationEditAttrUpdateDTO.getFieldEditedList());
                if (Objects.equals(singleAttrValuePojo.getAttr(), QuotationEnum.QUOTATION_TIME.getAttr())) {
                    if (Objects.nonNull(singleAttrValuePojo.getValue())) {
                        Long quotationTime = StringUtil.StringToLong(singleAttrValuePojo.getValue().toString());
                        for (QuotationEntityExt quotationEntityExt : quotationEntityExts) {
                            if (Objects.nonNull(quotationEntityExt.getData().get(QuotationEnum.EFFECTIVE_TIME.getAttr()))) {
                                Long effectiveTime = FastJsonHelper.getLongOrDefaultFromFormData(quotationEntityExt.getData(), QuotationEnum.EFFECTIVE_TIME.getAttr(), 0L);
                                if (quotationTime > effectiveTime) {
                                    throw new XbbException(QuotationErrorCodeEnum.API_ERROR_246003);
                                }
                            }
                        }
                    }
                } else if (Objects.equals(singleAttrValuePojo.getAttr(), QuotationEnum.EFFECTIVE_TIME.getAttr())) {
                    if (Objects.nonNull(singleAttrValuePojo.getValue())) {
                        Long effectiveTime = StringUtil.StringToLong(singleAttrValuePojo.getValue().toString());
                        for (QuotationEntityExt quotationEntityExt : quotationEntityExts) {
                            Long quotationTime = FastJsonHelper.getLongOrDefaultFromFormData(quotationEntityExt.getData(), QuotationEnum.QUOTATION_TIME.getAttr(), 0L);
                            if (quotationTime > effectiveTime) {
                                throw new XbbException(QuotationErrorCodeEnum.API_ERROR_246003);
                            }
                        }
                    }
                }

                QuotationUpdateBatchDTO quotationUpdateBatchDTO = new QuotationUpdateBatchDTO();
                BeanUtil.copyProperties(quotationEditAttrUpdateDTO, quotationUpdateBatchDTO);
                quotationUpdateBatchDTO.setQuotationUpdateDTOList(quotationUpdateDTOS);
                updateBatch(quotationUpdateBatchDTO);

                if (QuotationEnum.STATUS.getAttr().equals(singleAttrValuePojo.getAttr())) {
                    // 推送
                    try {
                        PaasFormExplainEntity planExplain = paasFormExplainModel.getByBusinessType(businessType, corpid);
                        if (Objects.isNull(planExplain)) {
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
                        }
                        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMapByAttr(planExplain.getExplains(), QuotationEnum.STATUS.getAttr());
                        FieldAttrEntity statusAttrEntity = explainMap.get(QuotationEnum.STATUS.getAttr());
                        String newStatus = singleAttrValuePojo.getValue().toString();
                        if (Objects.nonNull(statusAttrEntity)) {
                            List<ItemPoJo> items = statusAttrEntity.getItems();
                            for (ItemPoJo itemPoJo : items) {
                                if (Objects.equals(itemPoJo.getValue(), newStatus)) {
                                    newStatus = itemPoJo.getText();
                                }
                            }
                        }
                        for (QuotationEntityExt quotationEntityExt : quotationEntityExts) {
                            Long quotationId = quotationEntityExt.getId();
                            String name = FastJsonHelper.getStringOrDefaultFromFormData(quotationEntityExt.getData(), QuotationEnum.NAME.getAttr(), "");

                            QuotationEntityExt quotationEntity = new QuotationEntityExt();
                            BeanUtil.copyProperties(quotationEntityExt, quotationEntity);
                            List<String> pushUserList = pushHelper.getUserIdListByPushSetRule(corpid, PushTypeEnum.QUOTATION_STATUS_PUSH.getCode(), PushTypeEnum.QUOTATION_STATUS_PUSH.getSubCode(), quotationEditAttrUpdateDTO.getLoginUser(), quotationEntity);
                            PushRefTypePojo.Options options = new PushRefTypePojo.Options(quotationEntity.getAppId(), quotationEntity.getMenuId(), quotationEntity.getFormId(), quotationId, Collections.singletonList(quotationId), SaasMarkEnum.SAAS.getCode(), businessType, businessType);
                            MessageRabbitMqDTO messageRabbitMqDTO = new MessageRabbitMqDTO(corpid, pushUserList, Collections.singletonList(quotationId), 0, null, I18nMessageUtil.getMessage(QuotationPushConstant.QUOTATAION_CHANGE_TITLE), String.format(I18nMessageUtil.getMessage(QuotationPushConstant.QUOTATAION_CHANGE_CONTENT), quotationEditAttrUpdateDTO.getLoginUserName(), name, newStatus), null, options);
                            baseProducer.sendMessage(PushTypeEnum.QUOTATION_STATUS_PUSH, messageRabbitMqDTO);
                        }
                    } catch (Exception e) {
                        LOG.error("报价单批量编辑报价状态变更消息推送", e);
                    }
                }
            }

            // 批量编辑日志
            List<Long> dataIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (QuotationEntityExt item : quotationEntityExts) {
                dataIdList.add(item.getId());
            }

            if(Objects.nonNull(isBatch)){
                List<QuotationEntityExt> newQuotationEntityExts = quotationModel.findEntitys(param);
                List<PaasFormDataEntity> newDataList = new ArrayList<>();
                List<PaasFormDataEntity> oldDataList = new ArrayList<>();
                BeanUtil.copyPropertiesList(quotationEntityExts,oldDataList,PaasFormDataEntity.class);
                BeanUtil.copyPropertiesList(newQuotationEntityExts,newDataList,PaasFormDataEntity.class);
                OperationLogHandle operationLogHandle = operationLogFactory.getOperationLogHandle(saasMark,businessType);
                UpdateBatchOperationLogDTO updateBatchOperationLogDTO = new UpdateBatchOperationLogDTO(corpid,userId,loginUserName,dataIdList.size(),quotationEditAttrUpdateDTO.getHttpHeader(),
                        quotationEditAttrUpdateDTO.getLogFieldEditedList(), newDataList,oldDataList,formId,businessType,isBatch);;
                operationLogHandle.updateBatch(updateBatchOperationLogDTO);
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("quotationServiceImpl.batchEditAttr 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return new BaseVO();
    }

    @Override
    public List<AggSumVO> aggAvgByField(List<AggSumVO> numCountList, FormDataSummaryDTO formDataSummaryDTO, List<AggSumDTO> aggAvgFieldList, NativeSearchQuery searchQuery) throws XbbException {
        List<AggSumVO> aggAvgResultList = new ArrayList<>();
        if (numCountList.isEmpty()) {
            return aggAvgResultList;
        }
        Map<String, AggSumVO> numListMap = new HashMap<>(numCountList.size());
        numCountList.forEach((item)->{
            numListMap.put(item.getAttr(), item);
        });
        for (AggSumDTO item : aggAvgFieldList) {
            String attr = item.getAttr();
            AggSumVO aggSumVO = new AggSumVO();
            aggSumVO.setAttr(attr);
            aggSumVO.setName(item.getName());
            Integer accuracy = item.getFieldAttrEntity().getAccuracy();
            //报价金额
            AggSumVO amount = numListMap.get(QuotationEnum.AMOUNT.getAttr());
            if (QuotationEnum.GROSS_PROFIT_RATE.getAttr().equals(attr) && Objects.nonNull(amount)) {
                Double grossProfitTotal = Double.parseDouble(numListMap.get(QuotationEnum.GROSS_PROFIT.getAttr()).getValue().toString());
                Double allAmount = Double.parseDouble(amount.getValue().toString());
                // 预估毛利率 = 预估毛利/报价金额
                Double grossProfitRate = allAmount == 0D ? 0D : Arith.div(grossProfitTotal, allAmount) * 100;
                String value = attrDecimalPrecisionHelper.formatMoneyPrecision(grossProfitRate, accuracy);
                aggSumVO.setValue(value + "%");
            } else if (Objects.equals(attr, QuotationEnum.DISCOUNT.getAttr())) {
                List<AggSumDTO> summaryAttrList = new ArrayList<>();
                AggSumDTO aggSumDTO = new AggSumDTO();
                aggSumDTO.setAttr(QuotationEnum.DISCOUNT.getAttr());
                aggSumDTO.setField(QuotationEnum.getEsAttr4Keyword(QuotationEnum.DISCOUNT));
                aggSumDTO.setName(QuotationEnum.DISCOUNT.getAttrName());
                summaryAttrList.add(aggSumDTO);

                List<AggSumVO> discount = esHelper.aggAvgByField(IndexTypeEnum.IDX_SAAS_QUOTATION.getIndex(), IndexTypeEnum.IDX_SAAS_QUOTATION.getType(), summaryAttrList,searchQuery);
                if (!discount.isEmpty()) {
                    AggSumVO aggSumVO1 = discount.get(0);
                    aggSumVO.setValue(aggSumVO1.getValue());
                }
            }
            aggAvgResultList.add(aggSumVO);
        }
        return aggAvgResultList;
    }

    @Override
    public PagingProductVO getPagingProduct(PagingProductDTO pagingProductDTO) throws XbbException {
        PagingProductVO pagingProductVO = new PagingProductVO();
        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, pagingProductDTO.getCorpid());
        modelMap.put(ParameterConstant.QUOTATION_ID, pagingProductDTO.getDataId());
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        modelMap.put(ParameterConstant.PAGE,  pagingProductDTO.getPage());
        modelMap.put(ParameterConstant.ORDER_BY_STR, BasicConstant.SORT);
        PageHelper pageHelper = PageHelperUtil.getPageHelper(modelMap, quotationProductModel, pagingProductDTO.getPageSize());
        List<QuotationProductEntity> quotationProductList = (List<QuotationProductEntity>) PageHelperUtil.getEntityList(modelMap, pageHelper, quotationProductModel);
        if (pagingProductDTO.getUpdateDataTypeEnum().isDetail()) {
            DetailProductVO detailProductVO = formatProduct4DetailShow(quotationProductList, pagingProductDTO);
            pagingProductVO.setProductDataArr(detailProductVO.getProductDataArr());
        }
        pagingProductVO.setPageHelper(pageHelper);
        return pagingProductVO;
    }

    private DetailProductVO formatProduct4DetailShow(List<QuotationProductEntity> quotationProductList, PagingProductDTO pagingProductDTO) throws XbbException {
        DetailProductVO detailProductVO = new DetailProductVO();
        JSONArray productArray = new JSONArray();
        for (QuotationProductEntity quotationProductEntity : quotationProductList) {
            if (Objects.nonNull(quotationProductEntity.getBusinessUnit())) {
                quotationProductEntity.setProductNum(Arith.div(quotationProductEntity.getProductNum(), quotationProductEntity.getRate()));
                quotationProductEntity.setProductUnit(quotationProductEntity.getBusinessUnit().toString());
                JSONObject priceData = quotationProductEntity.getPriceData();
                if (Objects.nonNull(priceData)  && !priceData.isEmpty()) {
                    quotationProductEntity.setHistoricalPrice(priceData.getDouble(SelectProductEnum.PRICE.getAttr()));
                    quotationProductEntity.setPrice(priceData.getDouble(SelectProductEnum.SELLING_PRICE.getAttr()));
                }
            }
            JSONObject json = quotationProductEntity.getData() == null ? new JSONObject() : quotationProductEntity.getData();
            for (QuotationProductEnum quoatationProductEnum : QuotationProductEnum.values()) {
                if (!UpdateDataTypeEnum.DETAIL.formatShow(quoatationProductEnum.getShowType())) {
                    continue;
                }
                String attr = quoatationProductEnum.getAttr();
                switch (quoatationProductEnum) {
                    case PRODUCT:
                        json.put(attr, quotationProductEntity.getProductId());
                        break;
                    case PRICE:
                        json.put(attr,quotationProductEntity.getHistoricalPrice());
                        break;
                    case DISCOUNT:
                        json.put(attr, quotationProductEntity.getDiscount());
                        break;
                    case SELLING_PRICE:
                        json.put(attr, quotationProductEntity.getPrice());
                        break;
                    case NUM:
                        json.put(attr, quotationProductEntity.getProductNum());
                        break;
                    case MEMO:
                        json.put(attr, quotationProductEntity.getMemo());
                        break;
                    case UNIT:
                        json.put(attr, quotationProductEntity.getProductUnit());
                        break;
                    case SUBTOTAL:
                        json.put(attr, Arith.mul(quotationProductEntity.getPrice(), quotationProductEntity.getProductNum()));
                        break;
                    default:
                        break;
                }
            }
            json.put(BusinessConstant.PRODUCT_SUB_ID, quotationProductEntity.getId());
            json.put(BusinessConstant.PARENT_ID, quotationProductEntity.getParentId());
            productArray.add(json);
        }
        detailProductVO.setProductDataArr(productArray);
        return detailProductVO;
    }

    @Override
    public void formatProduct4Show2(Long dataId, String corpid, JSONObject data, UpdateDataTypeEnum updateDataTypeEnum) throws XbbException {
        quotationModel.formatProduct4Show2(dataId, corpid, data, updateDataTypeEnum);
    }

    @Override
    public void formatProduct4Show3(List<QuotationProductEntity> quotationProductEntityList, JSONObject productData, UpdateDataTypeEnum updateDataTypeEnum, String corpid) throws XbbException {
        quotationModel.formatProduct4Show3(quotationProductEntityList, productData, updateDataTypeEnum, corpid);
    }

    @Override
    public JSONObject formatSingleProduct(QuotationProductEntity quotationProductEntity) {
        return quotationModel.formatSingleProduct(quotationProductEntity);
    }

    @Override
    public Map<Long,String> getQuotationNameMap(List<Long> handoverIdSet, String corpid) throws XbbException {
        Map<Long,String> quotationNameMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (handoverIdSet.isEmpty()){
            return quotationNameMap;
        }
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(),handoverIdSet));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_QUOTATION.getType()));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(boolQueryBuilder);
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, handoverIdSet.size());
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_QUOTATION.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntity> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest,PaasFormDataEntity.class);
        for (PaasFormDataEntity entity : esEntities.getContent()){
            quotationNameMap.put(entity.getDataId(),entity.getData().getString(QuotationEnum.NAME.getAttr()));
        }
        return quotationNameMap;
    }

    @Override
    public void updateBatchLabelAttr(AddLabelDTO addLabelDTO, List<PaasFormDataEntityExt> addBatchList, Boolean addOrDelete) throws XbbException {
        QuotationUpdateBatchDTO quotationUpdateBatchDTO = new QuotationUpdateBatchDTO();
        BeanUtil.copyProperties(addLabelDTO, quotationUpdateBatchDTO);
        List<QuotationUpdateDTO> quotationList = new ArrayList<>();
        addBatchList.forEach(item->{
            QuotationUpdateDTO quotationUpdateDTO = new QuotationUpdateDTO();
            quotationUpdateDTO.setData(item.getData());
            quotationUpdateDTO.setId(item.getId());
            quotationList.add(quotationUpdateDTO);
        });
        quotationUpdateBatchDTO.setQuotationUpdateDTOList(quotationList);
        updateBatch(quotationUpdateBatchDTO);

    }

    @Override
    public void afterSaveForWorkflow(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        JSONObject newData = saasFormSaveDTO.getNewData();
        Long quotationId = newPaasFormDataEntity.getId();
        String corpid = newPaasFormDataEntity.getCorpid();
        Boolean isNew = saasFormSaveDTO.getIsNew();

        // 团队保存
        teamDataHelp.saveUserTeam(saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), quotationId, newPaasFormDataEntity, saasFormSaveDTO.getIsImport(), true);
//        userTeamService.saveUserTeam(saasFormSaveDTO);

        // 报价单关联产品保存
        if (saasFormSaveDTO.getSaasNeedRedundantAttrPoJo().getAttrCanSee(QuotationEnum.PRODUCT.getAttr())) {
            try {
                JSONArray productArray = newData.getJSONArray(QuotationEnum.PRODUCT.getAttr());

                if (!Objects.equals(productArray, null)) {
                    saveProduct2(productArray, corpid, quotationId, isNew);
                }
            } catch (Exception e) {
                LOG.error("报价单保存关联产品", e);
            }
        }
    }

    @Override
    public void afterSaveForUpdateWorkflow(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        JSONObject newData = saasFormSaveDTO.getNewData();
        Long quotationId = newPaasFormDataEntity.getId();
        String corpid = newPaasFormDataEntity.getCorpid();
        Boolean isNew = saasFormSaveDTO.getIsNew();

        // 团队保存
        teamDataHelp.saveUserTeam(saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), quotationId, newPaasFormDataEntity, saasFormSaveDTO.getIsImport(), true);

        // 报价单关联产品保存
        if (saasFormSaveDTO.getSaasNeedRedundantAttrPoJo().getAttrCanSee(QuotationEnum.PRODUCT.getAttr())) {
            try {
                JSONArray productArray = newData.getJSONArray(QuotationEnum.PRODUCT.getAttr());
                //saveProduct(productArray, corpid, quotationId, saasFormSaveDTO.getIsImport());
                if (!Objects.equals(productArray, null)) {
                    saveProduct2(productArray, corpid, quotationId, isNew);
                }
            } catch (Exception e) {
                LOG.error("报价单保存关联产品", e);
            }
        }
    }

}
